Eureka解读

1. Eureka 简述

简单来说 ,Eureka 就是 Netflix 开源的一款提供服务注册和服务发现的产品,并且提供了 Java 客户端。当然在 SpringCloud 大力优化后的 Eureka,已经不仅仅只是用于 AWS 云,而是可以应用在任何需要使用注册中心的场景

Eureka 由两个组件组成:Eureka 服务端和 Eureka 客户端。Eureka 服务端就是注册中心。Eureka 客户端是一个 Java 客户端,用来简化与服务端的交互、作为轮询负载均衡器,并提供服务的故障切换支持

下面是 Eureka 的使用场景
在这里插入图片描述
从上面看 Eureka Server 担任注册中心的角色,提供了服务的发现和服务注册功能

  • Service Provider 服务提供者:将自身的服务注册到 Eureka Server,同时通过心跳检查服务的运行状态
  • Service Consumer 服务调用者:从 Eureka Server 得到注册的服务列表,找到对应的服务地址再调用并使用

2. Eureka Server 服务端的核心功能点

在这里插入图片描述

2.1. Eureka 客户端的注册

Eureka 的客户端服务启动的时候,它会发起一个 HttpPOST 请求到 Eureka 的服务端(注册中心),用于注册自己的信息

Eureka 的服务端(注册中心)保存 Eureka 客户端注册进来的信息实际上是一个 Map

private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
  • 第一个 String 代表:客户端的服务名称,key = spring.application.name
  • 第二个 String 代表:该客户端实例的 ID(key = instanceId,因为一个服务有时不止一个实例)
  • Lease<InstanceInfo> 代表:该服务的 IP + 该服务的 HOST + 该服务的状态

2.2. Eureka 客户端的续约

Eureka 的客户端启动并成功注册到 Eureka 的服务端(注册中心)后, Eureka 的客户端会每隔 30 秒发送一次心跳(实际上就是 Http 的请求)来续约,通过续约来告知 Eureka 的服务端该 Eureka 的客户端还仍然存在。正常情况下,如果 Eureka 的服务端在 90 秒仍然没有收到 Eureka 的客户端的心跳,它会将实例从其注册表中删除,建议不要更改续约时间间隔

# 服务续约任务的调用间隔时间,默认为 30 秒
eureka.instance.lease-renewal-interval-in-seconds=30

# 服务失效的时间,默认为 90 秒
eureka.instance.lease-expiration-duration-in-seconds=90

2.3. Eureka 客户端的下线与剔除

Eureka 的客户端服务实例关闭时,服务实例会向 Eureka 服务器发送服务下线请求。发送请求后,该服务实例信息将从 Eureka 服务器的实例注册列表中删除

DiscoveryManager.getInstance().shutdownComponent();

2.4. Eureka 客户端拉取注册表信息

Eureka Client 每隔 30s 会从 Eureka 服务器端拉取注册表信息,并将其缓存在本地,客户端会使用该信息查找其他服务,从而进行远程调用。每次返回注册列表信息可能与 Eureka Client 的缓存信息不同,Eureka Client 自动处理。当所有的 Eureka Server 节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者,但是当服务有更改的时候会出现信息不一致

如果由于某种原因导致注册列表信息不能及时匹配,Eureka Client 则会重新获取整个注册表信息。Eureka Server 缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka ClientEureka Server 可以使用 JSON/XML 格式进行通讯。在默认情况下 Eureka Client 使用压缩 JSON 格式来获取注册列表的信息

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

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

2.5. Eureka 客户端的远程调用

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

2.6. Eureka 服务器端之间信息同步

Eureka Client 通过注册、心跳机制成功注册和续约后,Eureka Server 节点之间会同步当前客户端的状态信息

2.7. Eureka 服务端自我保护机制

默认情况下,如果 Eureka Server90s 内没有接收到某个微服务实例的心跳,它会将该实例从其注册表中删除。但是,在微服务架构下服务之间通常都是跨进程调用,网络通信往往面临各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。为了解决这个问题,Eureka 引入了自我保护机制,也就是如果在 15 分钟内超过 85% 的节点都没有正常的心跳,那么 Eureka 就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况

  • Eureka 不再从注册列表中移除因为长时间没有心跳而应该过期的服务
  • Eureka 仍然能够接受新服务的注册和查询请求,但是不会同步到其他节点上(既保证当前节点依然可用)
  • 当网络恢复正常时,当前实例新的注册信息会被同步到其他节点上

在这里插入图片描述
Eureka 自我保护机制是为了防止误杀服务而提供的一个机制

  • 当个别客户端出现心跳失联时,则认为是客户端的问题,剔除掉客户端
  • Eureka 捕获到大量的心跳失联时,则认为可能是网络问题,进入自我保护机制
  • 当客户端心跳恢复时,Eureka 会自动退出自我保护机制

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

# 开启或者关闭保护机制,生产环境建议打开
eureka.server.enable-self-preservation=true

3. Eureka 的架构原理

再来看看 Eureka 集群的架构工作原理。我们假设有三台 Eureka Server 组成的集群,第一台 Eureka Server 在北京机房,另外两台 Eureka Server 在上海和西安机房。这样三台 Eureka Server 就组建成了一个跨区域的高可用集群,只要三个地方的任意一个机房不出现问题,都不会影响整个架构的稳定性

在这里插入图片描述

  • 从图中可以看出 Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点
  • 如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中
  • 另外 Eureka Server 的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。所以,如果存在多个节点,只需要将节点之间两两连接起来形成通路,那么其它注册中心都可以共享信息。每个 Eureka Server 同时也是 Eureka Client,多个 Eureka Server 之间通过 P2P 的方式完成服务注册表的同步
  • Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的

3.1. Eureka 分区

Eureka 提供了 RegionZone 两个概念来进行分区,这两个概念均来自于亚马逊的 AWS

  • region:可以理解为地理上的不同区域,比如亚洲地区,中国区或者深圳等等。没有具体大小的限制。根据项目具体的情况,可以自行合理划分 region
  • zone:可以简单理解为 region 内的具体机房,比如说 region 划分为深圳,然后深圳有两个机房,就可以在此 region 之下划分出 zone1、zone2 两个 zone

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

4. Eureka 的工作流程

  • Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息
  • Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务
  • Eureka Client 会每 30sEureka Server 发送一次心跳请求,证明客户端服务正常
  • Eureka Server90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例
  • 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端
  • Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式
  • Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地
  • 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存
  • Eureka Client 获取到目标服务器信息,发起服务调用
  • Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除

5. Eureka Server 的数据存储与缓存机制

5.1. 数据存储层

Eureka 的服务端(注册中心)保存 Eureka 客户端注册进来的信息实际上是一个 Map

private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
  • 第一个 String 代表:客户端的服务名称,key = spring.application.name
  • 第二个 String 代表:该客户端实例的 ID(key = instanceId,因为一个服务有时不止一个实例)
  • Lease<InstanceInfo> 代表:该服务的 IP + 该服务的 HOST + 该服务的状态

5.2. 缓存层

Eureka Server 为了提高响应效率,在缓存层面提供了两层的缓存结构

  • 一级缓存:readOnlyCacheMap,它本质上是一个 ConcurrentHashMap。依赖定时的从 readWriteCacheMap 同步数据,默认同步间隔时间是 30s。主要是为了供 Eureka Client 获取注册信息时使用。它的缓存更新依赖于定时器的更新,通过和 readWriteCacheMap 的值做对比,如果数据不一致,则以 readWriteCacheMap 的数据为准
  • 二级缓存:readWriteCacheMap,它本质上是一个 Guava 缓存 readWriteCacheMap:它的数据主要同步于 ConcurrentHashMap 数据存储层。当获取缓存时判断缓存中是否没有数据,如果不存在此数据,则通过 CacheLoaderload 方法去加载,加载成功之后将数据放入缓存,同时返回数据。它的缓存过期时间是 180s,当服务下线,注册,状态改变等都会来清除缓存中的数据

6. Eureka Client 的缓存机制

  • Eureka Client 启动时会全量拉取注册表信息,启动完成后,会每隔 30sEureka Server 增量拉取信息,并保存在本地的缓存中
  • Eureka Client 增量拉取失败或者增量拉取之后对比 HashCode 发现不一致,就会执行全量拉取,同样会更新保存到本地的缓存
  • 对于服务的调用,如果涉及到 Ribbon 的负载均衡,而 Ribbon 对于这个服务实例列表也有自己的缓存,这个缓存每隔 30sEureka Client 的缓存更新

这么多的缓存机制可能就会造成一些问题,一个服务启动后可能最长需要 90s 才能被其它服务感知到:

  1. 首先,Eureka Server 会维护每 30s 更新的响应缓存
  2. Eureka Client 对已经获取到的注册信息也做了 30s 缓存
  3. 负载均衡组件 Ribbon 也有 30s 缓存

这三个缓存加起来,就有可能导致服务注册最长延迟 90s ,这个需要我们在特殊业务场景中注意其产生的影响

7. Eureka Server 的常用配置

#服务端开启自我保护模式,前面章节有介绍
eureka.server.enable-self-preservation=true

#扫描失效服务的间隔时间(单位毫秒,默认是60*1000)即60秒
eureka.server.eviction-interval-timer-in-ms= 60000

#间隔多长时间,清除过期的 delta 数据
eureka.server.delta-retention-timer-interval-in-ms=0

#请求频率限制器
eureka.server.rate-limiter-burst-size=10

#是否开启请求频率限制器
eureka.server.rate-limiter-enabled=false

#请求频率的平均值
eureka.server.rate-limiter-full-fetch-average-rate=100

#是否对标准的client进行频率请求限制。如果是false,则只对非标准client进行限制
eureka.server.rate-limiter-throttle-standard-clients=false

#注册服务、拉去服务列表数据的请求频率的平均值
eureka.server.rate-limiter-registry-fetch-average-rate=500

#设置信任的client list
eureka.server.rate-limiter-privileged-clients=

#在设置的时间范围类,期望与client续约的百分比
eureka.server.renewal-percent-threshold=0.85

#多长时间更新续约的阈值
eureka.server.renewal-threshold-update-interval-ms=0

#对于缓存的注册数据,多长时间过期
eureka.server.response-cache-auto-expiration-in-seconds=180

#多长时间更新一次缓存中的服务注册数据
eureka.server.response-cache-update-interval-ms=0

#缓存增量数据的时间,以便在检索的时候不丢失信息
eureka.server.retention-time-in-m-s-in-delta-queue=0

#当时间戳不一致的时候,是否进行同步
eureka.server.sync-when-timestamp-differs=true

#是否采用只读缓存策略,只读策略对于缓存的数据不会过期。
eureka.server.use-read-only-response-cache=true


################server node 与 node 之间关联的配置#####################
#发送复制数据是否在request中,总是压缩
eureka.server.enable-replicated-request-compression=false

#指示群集节点之间的复制是否应批处理以提高网络效率
eureka.server.batch-replication=false

#允许备份到备份池的最大复制事件数量。而这个备份池负责除状态更新的其他事件。可以根据内存大小,超时和复制流量,来设置此值得大小
eureka.server.max-elements-in-peer-replication-pool=10000

#允许备份到状态备份池的最大复制事件数量
eureka.server.max-elements-in-status-replication-pool=10000

#多个服务中心相互同步信息线程的最大空闲时间
eureka.server.max-idle-thread-age-in-minutes-for-peer-replication=15

#状态同步线程的最大空闲时间
eureka.server.max-idle-thread-in-minutes-age-for-status-replication=15

#服务注册中心各个instance相互复制数据的最大线程数量
eureka.server.max-threads-for-peer-replication=20

#服务注册中心各个instance相互复制状态数据的最大线程数量
eureka.server.max-threads-for-status-replication=1

#instance之间复制数据的通信时长
eureka.server.max-time-for-replication=30000

#正常的对等服务instance最小数量。-1表示服务中心为单节点
eureka.server.min-available-instances-for-peer-replication=-1

#instance之间相互复制开启的最小线程数量
eureka.server.min-threads-for-peer-replication=5

#instance之间用于状态复制,开启的最小线程数量
eureka.server.min-threads-for-status-replication=1

#instance之间复制数据时可以重试的次数
eureka.server.number-of-replication-retries=5

#eureka节点间间隔多长时间更新一次数据。默认10分钟
eureka.server.peer-eureka-nodes-update-interval-ms=600000

#eureka服务状态的相互更新的时间间隔。
eureka.server.peer-eureka-status-refresh-time-interval-ms=0

#eureka对等节点间连接超时时间
eureka.server.peer-node-connect-timeout-ms=200

#eureka对等节点连接后的空闲时间
eureka.server.peer-node-connection-idle-timeout-seconds=30

#节点间的读数据连接超时时间
eureka.server.peer-node-read-timeout-ms=200

#eureka server 节点间连接的总共最大数量
eureka.server.peer-node-total-connections=1000

#eureka server 节点间连接的单机最大数量
eureka.server.peer-node-total-connections-per-host=10

#在服务节点启动时,eureka尝试获取注册信息的次数
eureka.server.registry-sync-retries=

#在服务节点启动时,eureka多次尝试获取注册信息的间隔时间
eureka.server.registry-sync-retry-wait-ms=

#当eureka server启动的时候,不能从对等节点获取instance注册信息的情况,应等待多长时间。
eureka.server.wait-time-in-ms-when-sync-empty=0

8. Eureka Client 的常用配置

#该客户端是否可用
eureka.client.enabled=true

#实例是否在eureka服务器上注册自己的信息以供其他服务发现,默认为true
eureka.client.register-with-eureka=false

#此客户端是否获取eureka服务器注册表上的注册信息,默认为true
eureka.client.fetch-registry=false

#是否过滤掉,非UP的实例。默认为true
eureka.client.filter-only-up-instances=true

#与Eureka注册服务中心的通信zone和url地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

#client连接Eureka服务端后的空闲等待时间,默认为30 秒
eureka.client.eureka-connection-idle-timeout-seconds=30

#client连接eureka服务端的连接超时时间,默认为5秒
eureka.client.eureka-server-connect-timeout-seconds=5

#client对服务端的读超时时长
eureka.client.eureka-server-read-timeout-seconds=8

#client连接all eureka服务端的总连接数,默认200
eureka.client.eureka-server-total-connections=200

#client连接eureka服务端的单机连接数量,默认50
eureka.client.eureka-server-total-connections-per-host=50

#执行程序指数回退刷新的相关属性,是重试延迟的最大倍数值,默认为10
eureka.client.cache-refresh-executor-exponential-back-off-bound=10

#执行程序缓存刷新线程池的大小,默认为5
eureka.client.cache-refresh-executor-thread-pool-size=2

#心跳执行程序回退相关的属性,是重试延迟的最大倍数值,默认为10
eureka.client.heartbeat-executor-exponential-back-off-bound=10

#心跳执行程序线程池的大小,默认为5
eureka.client.heartbeat-executor-thread-pool-size=5

# 询问Eureka服务url信息变化的频率(s),默认为300秒
eureka.client.eureka-service-url-poll-interval-seconds=300

#最初复制实例信息到eureka服务器所需的时间(s),默认为40秒
eureka.client.initial-instance-info-replication-interval-seconds=40

#间隔多长时间再次复制实例信息到eureka服务器,默认为30秒
eureka.client.instance-info-replication-interval-seconds=30

#从eureka服务器注册表中获取注册信息的时间间隔(s),默认为30秒
eureka.client.registry-fetch-interval-seconds=30

# 获取实例所在的地区。默认为us-east-1
eureka.client.region=us-east-1

#实例是否使用同一zone里的eureka服务器,默认为true,理想状态下,eureka客户端与服务端是在同一zone下
eureka.client.prefer-same-zone-eureka=true

# 获取实例所在的地区下可用性的区域列表,用逗号隔开。(AWS)
eureka.client.availability-zones.china=defaultZone,defaultZone1,defaultZone2

#eureka服务注册表信息里的以逗号隔开的地区名单,如果不这样返回这些地区名单,则客户端启动将会出错。默认为null
eureka.client.fetch-remote-regions-registry=

#服务器是否能够重定向客户端请求到备份服务器。 如果设置为false,服务器将直接处理请求,如果设置为true,它可能发送HTTP重定向到客户端。默认为false
eureka.client.allow-redirects=false

#客户端数据接收
eureka.client.client-data-accept=

#增量信息是否可以提供给客户端看,默认为false
eureka.client.disable-delta=false

#eureka服务器序列化/反序列化的信息中获取“_”符号的的替换字符串。默认为“__“
eureka.client.escape-char-replacement=__

#eureka服务器序列化/反序列化的信息中获取“$”符号的替换字符串。默认为“_-”
eureka.client.dollar-replacement="_-"

#当服务端支持压缩的情况下,是否支持从服务端获取的信息进行压缩。默认为true
eureka.client.g-zip-content=true

#是否记录eureka服务器和客户端之间在注册表的信息方面的差异,默认为false
eureka.client.log-delta-diff=false

# 如果设置为true,客户端的状态更新将会点播更新到远程服务器上,默认为true
eureka.client.on-demand-update-status-change=true

#此客户端只对一个单一的VIP注册表的信息感兴趣。默认为null
eureka.client.registry-refresh-single-vip-address=

#client是否在初始化阶段强行注册到服务中心,默认为false
eureka.client.should-enforce-registration-at-init=false

#client在shutdown的时候是否显示的注销服务从服务中心,默认为true
eureka.client.should-unregister-on-shutdown=true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值