赞
踩
Eureka
简述简单来说 ,Eureka
就是 Netflix
开源的一款提供服务注册和服务发现的产品,并且提供了 Java
客户端。当然在 SpringCloud
大力优化后的 Eureka
,已经不仅仅只是用于 AWS
云,而是可以应用在任何需要使用注册中心的场景
Eureka
由两个组件组成:Eureka
服务端和 Eureka
客户端。Eureka
服务端就是注册中心。Eureka
客户端是一个 Java
客户端,用来简化与服务端的交互、作为轮询负载均衡器,并提供服务的故障切换支持
下面是 Eureka
的使用场景
从上面看 Eureka Server
担任注册中心的角色,提供了服务的发现和服务注册功能
Service Provider
服务提供者:将自身的服务注册到 Eureka Server
,同时通过心跳检查服务的运行状态Service Consumer
服务调用者:从 Eureka Server
得到注册的服务列表,找到对应的服务地址再调用并使用Eureka Server
服务端的核心功能点Eureka
客户端的注册当 Eureka
的客户端服务启动的时候,它会发起一个 Http
的 POST
请求到 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
+ 该服务的状态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
Eureka
客户端的下线与剔除当 Eureka
的客户端服务实例关闭时,服务实例会向 Eureka
服务器发送服务下线请求。发送请求后,该服务实例信息将从 Eureka
服务器的实例注册列表中删除
DiscoveryManager.getInstance().shutdownComponent();
Eureka
客户端拉取注册表信息Eureka Client
每隔 30s
会从 Eureka
服务器端拉取注册表信息,并将其缓存在本地,客户端会使用该信息查找其他服务,从而进行远程调用。每次返回注册列表信息可能与 Eureka Client
的缓存信息不同,Eureka Client
自动处理。当所有的 Eureka Server
节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者,但是当服务有更改的时候会出现信息不一致
如果由于某种原因导致注册列表信息不能及时匹配,Eureka Client
则会重新获取整个注册表信息。Eureka Server
缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka Client
和 Eureka Server
可以使用 JSON/XML
格式进行通讯。在默认情况下 Eureka Client
使用压缩 JSON
格式来获取注册列表的信息
# 启用服务消费者从注册中心拉取服务列表的功能
eureka.client.fetch-registry=true
# 设置服务消费者从注册中心拉取服务列表的间隔
eureka.client.registry-fetch-interval-seconds=30
Eureka
客户端的远程调用当 Eureka Client
从注册中心获取到服务提供者信息后,就可以通过 Http
请求调用对应的服务;服务提供者有多个时,Eureka Client
客户端会通过 Ribbon
自动进行负载均衡
Eureka
服务器端之间信息同步Eureka Client
通过注册、心跳机制成功注册和续约后,Eureka Server
节点之间会同步当前客户端的状态信息
Eureka
服务端自我保护机制默认情况下,如果 Eureka Server
在 90s
内没有接收到某个微服务实例的心跳,它会将该实例从其注册表中删除。但是,在微服务架构下服务之间通常都是跨进程调用,网络通信往往面临各种问题,比如微服务状态正常,网络分区故障,导致此实例被注销。为了解决这个问题,Eureka
引入了自我保护机制,也就是如果在 15
分钟内超过 85%
的节点都没有正常的心跳,那么 Eureka
就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况
Eureka
不再从注册列表中移除因为长时间没有心跳而应该过期的服务Eureka
仍然能够接受新服务的注册和查询请求,但是不会同步到其他节点上(既保证当前节点依然可用)
Eureka
自我保护机制是为了防止误杀服务而提供的一个机制
Eureka
捕获到大量的心跳失联时,则认为可能是网络问题,进入自我保护机制Eureka
会自动退出自我保护机制如果在保护期内刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,即会调用失败。对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等
# 开启或者关闭保护机制,生产环境建议打开
eureka.server.enable-self-preservation=true
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
集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的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
中获取信息
Eureka
的工作流程Eureka Server
启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate
同步注册表,每个 Eureka Server
都存在独立完整的服务注册表信息Eureka Client
启动时根据配置的 Eureka Server
地址去注册中心注册服务Eureka Client
会每 30s
向 Eureka Server
发送一次心跳请求,证明客户端服务正常Eureka Server
在 90s
内没有收到 Eureka Client
的心跳,注册中心则认为该节点失效,会注销该实例Eureka Server
统计到有大量的 Eureka Client
没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端Eureka Client
心跳请求恢复正常之后,Eureka Server
自动退出自我保护模式Eureka Client
定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地Eureka Client
会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存Eureka Client
获取到目标服务器信息,发起服务调用Eureka Client
程序关闭时向 Eureka Server
发送取消请求,Eureka Server
将实例从注册表中删除Eureka Server
的数据存储与缓存机制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
+ 该服务的状态Eureka Server
为了提高响应效率,在缓存层面提供了两层的缓存结构
readOnlyCacheMap
,它本质上是一个 ConcurrentHashMap
。依赖定时的从 readWriteCacheMap
同步数据,默认同步间隔时间是 30s
。主要是为了供 Eureka Client
获取注册信息时使用。它的缓存更新依赖于定时器的更新,通过和 readWriteCacheMap
的值做对比,如果数据不一致,则以 readWriteCacheMap
的数据为准readWriteCacheMap
,它本质上是一个 Guava
缓存 readWriteCacheMap
:它的数据主要同步于 ConcurrentHashMap
数据存储层。当获取缓存时判断缓存中是否没有数据,如果不存在此数据,则通过 CacheLoader
的 load
方法去加载,加载成功之后将数据放入缓存,同时返回数据。它的缓存过期时间是 180s
,当服务下线,注册,状态改变等都会来清除缓存中的数据Eureka Client
的缓存机制Eureka Client
启动时会全量拉取注册表信息,启动完成后,会每隔 30s
从 Eureka Server
增量拉取信息,并保存在本地的缓存中Eureka Client
增量拉取失败或者增量拉取之后对比 HashCode
发现不一致,就会执行全量拉取,同样会更新保存到本地的缓存Ribbon
的负载均衡,而 Ribbon
对于这个服务实例列表也有自己的缓存,这个缓存每隔 30s
从 Eureka Client
的缓存更新这么多的缓存机制可能就会造成一些问题,一个服务启动后可能最长需要 90s
才能被其它服务感知到:
Eureka Server
会维护每 30s
更新的响应缓存Eureka Client
对已经获取到的注册信息也做了 30s
缓存Ribbon
也有 30s
缓存这三个缓存加起来,就有可能导致服务注册最长延迟 90s
,这个需要我们在特殊业务场景中注意其产生的影响
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
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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。