Eureka原理分析


注:本文内容大部分来自网络资料整理,仅供个人学习使用,若有侵权,烦请告知
参考博文链接如下:
《Eureka工作原理》by代码爱烦恼
《Spring Cloud 学习笔记(1 / 3)》by巨輪
《Eureka原理剖析》by起岸星辰

一、Eureka相关概念

服务治理

Spring Cloud封装了Netflix 公司开发的Eureka模块来实现服务治理

在传统的RPC(Remote Procedure Call)远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

服务注册与发现

Eureka采用了C/S的设计架构,Eureka Sever作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在这里插入图片描述
服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息(包括它自身的元数据,比如 IP 地址、端口,运行状况指示符 URL,主页等),Eureka Server 内部有二层缓存机制来维护整个注册表。此外,Eureka Client也会定期从Server端拉取注册表信息,存储在本地缓存中
注:Eureka Server是在Eureka Client的基础上进一步封装的一个东西;也就是说客户端有的东西服务端也有。服务端额外多的东西就是对注册表的处理部分。

Renew: 服务续约
Eureka Client 会每隔 30 秒发送一次心跳来续约。 通过续约来告知 Eureka Server 该 Eureka Client 运行正常,没有出现问题。 默认情况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的续约,Server 端会将实例从其注册表中删除,此时间可配置,一般情况不建议更改。

Eviction 服务剔除
当 Eureka Client 和 Eureka Server 不再有心跳时,Eureka Server 会将该服务实例从服务注册列表中删除,即服务剔除。

Cancel: 服务下线
Eureka Client 在程序关闭时向 Eureka Server 发送取消请求。 发送请求后,该客户端实例信息将从 Eureka Server 的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:

DiscoveryManager.getInstance().shutdownComponent()

GetRegisty: 获取注册列表信息
Eureka Client 从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。
获取服务是服务消费者的基础,注意两个参数:

# 启用服务消费者从注册中心拉取服务列表的功能
eureka.client.fetch-registry=true

# 设置服务消费者从注册中心拉取服务列表的间隔
eureka.client.registry-fetch-interval-seconds=30

Remote Call: 远程调用
当 Eureka Client 从注册中心获取到服务提供者信息后,就可以通过 Http 请求调用对应的服务;服务提供者有多个时,Eureka Client 客户端会通过 Ribbon 自动进行负载均衡。

自我保护机制
默认情况下,如果 Eureka Server 在一定的 90s 内没有接收到某个微服务实例的心跳,会注销该实例。但是在微服务架构下服务之间通常都是跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。

固定时间内大量实例被注销,可能会严重威胁整个微服务架构的可用性。为了解决这个问题,Eureka 开发了自我保护机制,那么什么是自我保护机制呢?

Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 即会进入自我保护机制。
Eureka Server 进入自我保护机制,会出现以下几种情况:

  1. Eureka 不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
  2. Eureka 仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
  3. 当网络稳定时,当前实例新的注册信息会被同步到其它节点中

Eureka 自我保护机制是为了防止误杀服务而提供的一个机制。当个别客户端出现心跳失联时,则认为是客户端的问题,剔除掉客户端;当 Eureka 捕获到大量的心跳失败时,则认为可能是网络问题,进入自我保护机制;当客户端心跳恢复时,Eureka 会自动退出自我保护机制。

如果在保护期内刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,即会调用失败。对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。

二、Eureka服务端启动流程

  • 初始化环境配置
  • 读取服务端的配置信息,也就是读取eureka-server.properties配置文件;由于eureka中对这种配置类采用的是面向接口的方式,因此非常好扩展,在spring中是重新实现了这些配置类接口的。
    构建应用管理器;读取eureka-client.properties配置文件,选择其中的部分配置,基于构造者模式创建服务实例交给应用管理器。
  • 读取eureka-client.properties配置文件构建客户端信息;这里的操作和客户端的启动流程几乎就是一样的,因此这里就不做详细说明了。
  • 创建注册表感知器registry,这个也可以称为注册表管理器。这里会维护注册表信息。
  • 创建服务端集群节点信息管理器;也就是我们配置的集群地址信息,默认10分钟检查一次。
    基于上面的信息创建服务端的上下文信息;这里在进行初始化的时候会对相关资源进行初始化;
  • 启动相关的定时任务。从任意一个其他的服务端节点上拉取注册表信息;注意这里只有将fetchRegistry配置为true才是有效的(因为这里最终是从服务端中的客户端中的注册信息里面拿到的,这也是为什么网上很多说是从任意一个其他节点去拉取,因为客户端就是选择的一个去拉取的),同时将registry-sync-retries配置的值大于0(spring中默认值是0,也就是在spring-cloud中是不会执行这一步的)
  • 启动注册表感知器registry的定时;这个定时主要就是检查注册表中是否有过期的注册信息。
  • 最后进行监听器的绑定
    相关的流程图如下:
    在这里插入图片描述

三、Eureka客户端启动流程

Eureka客户端的启动主要就是几个定时和之后进行注册表维护的网络请求资源初始化。

  • 构建应用管理器;读取eureka-client.properties配置文件,选择其中的部分配置,基于构造者模式创建服务实例交给应用管理器。
  • 读取eureka-client.properties配置信息构建客户端的配置信息;
  • 根据上面的配置信息和应用管理器构建客户端;
  • 创建心跳、缓存等需要的线程池
  • 创建网络通信组件;后面发送注册信息、心跳信息这些请求都是通过它来处理的;
  • 判断是否需要拉取注册表信息,若是则会全量拉取一次注册表信息;
  • 启动相关的定时任务:注册表更新任务(默认30s执行一次)、心跳定时任务(默认30s执行一次)、创建服务状态更新定时任务(默认30s执行一次,这个就是留给我们自定义服务上下线状态的判断逻辑的);
  • 启动服务状态更新定时任务(第一次延迟40s执行);这里面就是向服务端发送注册信息的实现。
  • 最后进行监听器的绑定
    相关的流程图如下:
    在这里插入图片描述

四、Eureka注册表的原理

eureka的注册表中保存中服务的注册信息,下面我们通过如下几个点来对其原理进行简析。

注册表抓取和缓存机制
其基本流程图如下:
在这里插入图片描述
注册表的数据结构和缓存机制
eureka server中对注册表的信息进行多重缓存,分为:

  • 只读缓存(ConcurrentMap):会有定时任务默认每隔30s主动的去和读写缓存里面的信息同步一次;
  • 读写缓存(guava的LoadingCache):在创建LoadingCache的时候默认设置的过期时间是180s;
  • 注册表:这个就是实时的本地注册信息,每次客户端的注册信息更新后,都会实时的保存在这里;同时在更新它的时候会将读写缓存中的值设置为失效状态。
    注册表信息读取流程

注册表的拉取分为全量和增量;在初次拉取时使用的是全量,后面使用的都是增量拉取的。

全量拉取流程:

  • 服务端收到客户端的请求后,会直接从只读缓存里面取值,如果有就返回,否则进行下一步;
  • 只读缓存里面没有时,会从读写缓存里面取值,如果有就返回,同时将其设置达到只读缓存里面;否则进行下一步;
  • 读写缓存里面没有时,会触发LoadingCache的load方法,这里面会从本地注册表中取值返回。

增量拉取流程:

  • 服务端收到客户端的请求后,会直接从只读缓存里面取增量信息,如果有就返回,否则进行下一步;
  • 只读缓存里面没有时,会从读写缓存里面取增量信息,如果有就返回,同时将其设置达到只读缓存里面;否则进行下一步;
  • 读写缓存里面没有时,会触发LoadingCache的load方法,这里面会增量队列中获取变化的信息然后返回;
    在这里插入图片描述

心跳的请求也是在服务端自己处理完成后,会自动将这个请求转发给集群中的其他节点。心跳的操作就是更新注册信息中的租约时间,这里就不详细说明了。注意这种通知集群中其他节点的操作在失败后会不断的重试,同时正式由于有这个操作,因此服务端的fetchRegistry配置为false,集群间的注册信息依然可以正常同步的原因。

五、Eureka注册信息摘除

客户端的注册信息被摘除主要是这2种情况:1.客户端服务主动下线;2.服务异常。

客户端服务主动下线
客户端服务下线:主动取消注册信息,这种服务端直接接收请求然后删除即可;其流程图如下:
在这里插入图片描述
服务异常
客户端异常:没有发送取消请求或者是服务端没有正常接收和处理取消请求的情况下,此时就需要服务端自己定制一套注册信息过期机制,这也就是发送心跳的作用。

服务端中注册表信息过期检查的定时任务默认每隔60s检查一次,其大致流程如下:

判断的过期的依据是:当前时间戳 > (上一次发送租约的时间戳 + 过期时间(默认90s) + 补充时间(就是距离上一次执行任务的时间超过定时任务配置的60s执行一次的周期时间));但是由于在设置上一次发送租约的时间戳时候额外加上了一个过期时间;因此最终注册表的过期时间就至少是180s。
选择15%的过期注册信息,然后调用取消操作来删除注册信息;同时会通知集群中其他的节点。
在这里插入图片描述

六、Eureka 集群原理

在这里插入图片描述
从图中可以看出 Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。

如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。

另外 Eureka Server 的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。所以,如果存在多个节点,只需要将节点之间两两连接起来形成通路,那么其它注册中心都可以共享信息。每个 Eureka Server 同时也是 Eureka Client,多个 Eureka Server 之间通过 P2P 的方式完成服务注册表的同步。

Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的。

Eureka 分区
Eureka 提供了 Region 和 Zone 两个概念来进行分区,这两个概念均来自于亚马逊的 AWS:
region:可以理解为地理上的不同区域,比如亚洲地区,中国区或者深圳等等。没有具体大小的限制。根据项目具体的情况,可以自行合理划分 region。
zone:可以简单理解为 region 内的具体机房,比如说 region 划分为深圳,然后深圳有两个机房,就可以在此 region 之下划分出 zone1、zone2 两个 zone。

上图中的 us-east-1c、us-east-1d、us-east-1e 就代表了不同的 Zone。Zone 内的 Eureka Client 优先和 Zone 内的 Eureka Server 进行心跳同步,同样调用端优先在 Zone 内的 Eureka Server 获取服务列表,当 Zone 内的 Eureka Server 挂掉之后,才会从别的 Zone 中获取信息。

Eurka 保证 AP

Eureka Server 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka Client 在向某个 Eureka 注册时,如果发现连接失败,则会自动切换至其它节点。只要有一台 Eureka Server 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。

八、Eurka 工作流程总结

了解完 Eureka 核心概念,自我保护机制,以及集群内的工作原理后,我们来整体梳理一下 Eureka 的工作流程:

  1. Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息
  2. Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务
  3. Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常;此外,Eureka Client还会每隔30s 从Eureka Server增量地拉取注册信息表,更新本地注册信息表
  4. 当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例
  5. 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端
  6. 当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式
  7. 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存
  8. Eureka Client 获取到目标服务器信息,发起服务调用
  9. Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除,更改注册变更表以及读写缓存,同时将该下线信息转发至其他集群节点中
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值