哈喽大家好,这里是最锋利的矛。今天和大家一起了解一下老生常谈的eureka
几乎所有的分布式组件都逃不过CAP定律想必大家都知道,而eureka是基于高可用AP的理念来实现的,从而放弃了强一致性。大家是否也很好奇他具体是怎么实现的那么今天我们一起来学习一下
做为注册中心最重要的是什么?当然是用于服务的注册与发现喽,先来了解一下注册与发现的流程
注册与发现
注册
当eureka server启动后就可以作为服务注册中心,负责接收和管理所有服务实例的注册信息。在服务A、B、C启动时,它会通过HTTP POST请求向eureka server注册自己
eureka server为了能够记住过来注册都是谁,需要把他们都保存起来,大家可以把eureka server当成一个巨大的map
,事实上它的底层数据结构也确实是一个ConcurrentHashMap<String,Map<String, Lease<InstanceInfo>>>
map的key为要注册服务名称,value为Map<String, Lease>,这个map的key为服务实例的id,value是一个叫做Lease的类,value是一个叫做Lease的类,存储的类型为InstanceInfo,从名字可以看出来它包含服务的一些详细信息,比如ip、端口什么的,而这个Lease里面则会维护每个服务最近一次发送心跳的时间
发现
当服务C想要调用服务B时,会在服务C注册到eureka server时,通过http请求从eureka server获取当前注册的所有服务实例的列表,并获取的服务实例列表缓存在本地。费者会定期(默认每30秒)从eureka server拉取最新的服务实例列表,以更新本地缓存
在需要调用时会从本地缓存中查找目标服务的所有实例。服务C可能会使用某种负载均衡策略(如轮询、随机或基于权重的选择)来决定调用服务B的魔偶哥实例。一旦选择了服务实例,服务C就会使用该实例的地址和端口发起调用
并且在调用服务实例之前或之后,服务消费者可能会执行健康检查,确保目标服务实例是可用的,如果初次调用失败,服务消费者可能会重试调用另一个服务实例,或者使用重试机制再次尝试同一个服务实例
了解了注册与发现的流程,话说回来怎么来实现高可用的?这就不得不提eureka的多级缓存设计
多级缓存
为了提高数据访问速度、减少主数据存储的压力,并增强系统的整体性能和响应能力。在eureka服务发现机制中,使用了多级缓存的设计
如图所示在两个服务A注册到eureka server时,首先会存入内存中的注册列表,然后会立马同步到ReadWrite读写缓存中,然后eureka server中有一个线程会定时的同步信息到ReadOnly只读缓存中
当服务B要调用服务A时,首先会尝试从本地缓存中读取服务注册信息,如果本地缓存中的数据过期或不存在,则向eureka server 发起请求,eureka server接收到请求后,将从ReadOnly只读缓存中读取数据,因为这是最快的读取路径,如果ReadOnly只读缓存中的数据也过期或缺失,eureka server 将从内存中的注册列表中读取最新信息,并可能更新 readOnly只读缓存中。最终,eureka server将返回最新的服务注册信息给服务B,服务B收到信息后,会更新其本地缓存,以供后续请求使用。
有的朋友可能会问,如果无服务A在上线一台新的机器A2,只注册到了ReadWrite读写中,还没有同步进ReadOnly只读缓存中,那么服务B在调用服务A时岂不是发现不了新的机器,只能等到定时同步结束后才能访问到?
没错,这也就是eureka不能实现强一致cp的体现,只能实现最终的一致性,不过可以通过eureka的配置来控制这个同步时间,可以根据自己实际的业务来配置。
# application.yml
eureka:
instance:
...
server:
eviction-interval-timer-in-ms: 15000 # 将同步周期改为 15 秒
除了多级缓存的设计外,eureka还做了很多优化的设计
服务信息同步
关于服务信息同步,前面也提到了在首次注册进eureka时,服务会拉取eureka server中的注册表信息存到本地缓存中,但这里的信息同步主要是指eureka server集群内部的信息同步,而非直接意义上的服务间通信。那么平常时怎么实现服务间的信息同步呢?
答案是租约 (Lease)和心跳 (Heartbeat)
租约 (Lease)
在eureka中,每当一个服务实例注册到eureka server时,它就会获得一个租约(Lease)。租约实际上是一个有限期限的协议,它规定了服务实例必须多久向eureka server发送一次心跳以表明其仍然活跃和可用。租约有两个主要属性:
-
租约续期时间 (
leaseRenewalIntervalInSeconds
):服务实例必须向eureka server发送心跳的频率,默认为30秒。这个时间间隔定义了服务实例“租约”的续期频率。 -
租约到期时间 (
leaseExpirationDurationInSeconds
):eureka server在没有收到服务实例的心跳后等待多久才认为该服务实例不再可用,默认为90秒。这是租约的总持续时间。
心跳 (Heartbeat)
心跳是服务实例向eureka server发送的信号,表明它仍在运行并准备好接受请求。以下是心跳的工作流程:
-
服务实例注册:
- 当服务实例首次注册到eureka server时,它将获得一个租约,其中包括上述提到的租约续期时间和租约到期时间。
-
定期续期:
- 服务实例会按照租约续期时间的频率(默认30秒)向eureka server发送心跳,以更新其租约状态。
- 这些心跳通过HTTP PUT请求发送,通常指向
/eureka/apps/{appId}/{instanceId}
的URL,其中{appId}
是服务的应用标识符,{instanceId}
是服务实例的唯一标识符。
-
租约续期:
- 当eureka server接收到心跳时,它会更新服务实例的租约状态,将租约重置为有效状态。
- eureka server维护一个服务注册表,记录了所有已注册服务实例的信息和它们的租约状态。
-
租约到期与服务实例下线:
- 如果eureka server在租约到期时间内没有接收到服务实例的心跳,它将认为该服务实例可能已宕机或网络不通。
- 默认情况下,如果超过90秒没有收到心跳,eureka server会将该服务实例标记为不可用,并从服务注册表中移除。
- 然而,eureka具有自我保护模式,它可以防止在高并发的网络故障期间错误地剔除服务实例。在自我保护模式下,即使心跳未按时到达,eureka server也不会立即移除服务实例,而是等待网络状况恢复。
小结
心跳和租约管理与服务间的信息同步相关,对eureka的影响可以从以下几个方面来说
-
服务状态的实时性:
- 心跳和租约管理确保了eureka server上服务实例状态的实时性和准确性。这意呀着当一个服务实例下线或上线时,eureka server能够迅速反映这一变化,并将这些变化传播到整个eureka server集群中。
- 这样一来,当服务消费者请求服务提供者列表时,它们将得到最新的、反映了服务实例当前状态的信息。
-
集群间的同步:
- 当一个服务实例在某个eureka server上注册或更新其状态时,这个信息会被复制到eureka server集群中的其他节点。
- 这个过程是通过eureka server之间的复制机制实现的,其中涉及到心跳和租约管理的信息,确保了所有eureka server节点上的服务注册信息一致。
-
服务发现的一致性:
- eureka server集群中的信息同步机制保证了服务发现的一致性,即无论服务消费者连接到哪个eureka server节点,它都将得到相同的服务实例列表。
- 这对于分布式系统中服务间的可靠通信至关重要,确保了即使在网络分区或部分服务器故障的情况下,服务发现仍然能够正确工作。
总结
ok,今天主要从服务注册、发现以及eurea多级缓存和心跳的实现来理解了eureka中对高可用的实现
欢迎大家多多点赞留言,后续还有更多内容一起学习哦