Eureka 源码解析 —— 应用实例注册发现(六)之全量获取
来源:互联网 发布:即时通讯软件 编辑:程序博客网 时间:2024/05/16 04:19
摘要: 原创出处 http://www.iocoder.cn/Eureka/instance-registry-fetch-all/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文主要基于 Eureka 1.8.X 版本
- 1. 概述
- 2. Eureka-Client 发起全量获取
- 2.1 初始化全量获取
- 2.2 定时获取
- 2.3 刷新注册信息缓存
- 2.4 发起获取注册信息
- 3. Eureka-Server 接收全量获取
- 3.1 接收全量获取请求
- 3.2 响应缓存 ResponseCache
- 3.3 缓存读取
- 3.4 主动过期读写缓存
- 3.5 被动过期读写缓存
- 3.6 定时刷新只读缓存
- 请支持正版。下载盗版,等于主动编写低级 BUG 。
- 程序猿DD —— 《Spring Cloud微服务实战》
- 周立 —— 《Spring Cloud与Docker微服务架构实战》
- 两书齐买,京东包邮。
com.netflix.discovery.shared.Applications
,注册的应用集合。较为容易理解,点击 链接 链接查看带中文注释的类,这里就不啰嗦了。Applications 与 InstanceInfo 类关系如下:配置
eureka.shouldFetchRegistry = true
,开启从 Eureka-Server 获取注册信息。默认值:true
。- 调用
#fetchRegistry(false)
方法,从 Eureka-Server 全量获取注册信息,在 「2.4 发起获取注册信息」 详细解析。 - 初始化定时任务代码,和续租的定时任务代码类似,在 《Eureka 源码解析 —— 应用实例注册发现(二)之续租
》 有详细解析,这里不重复分享。 com.netflix.discovery.DiscoveryClient.CacheRefreshThread
,注册信息缓存刷新任务,实现代码如下:- 调用
#refreshRegistry(false)
方法,刷新注册信息缓存,在 「2.3 刷新注册信息缓存」 详细解析。
- 调用
- 第 3 至 28 行 :TODO[0009]:RemoteRegionRegistry
- 第 30 行 :调用
#fetchRegistry(false)
方法,从 Eureka-Server 获取注册信息,在 「2.4 发起获取注册信息」 详细解析。 第 31 至 36 行 :获取注册信息成功,设置注册信息的应用实例数,最后获取注册信息时间。变量代码如下:
第 38 至 53 行 :打印调试日志。
- 第 54 至 56 行 :打印异常日志。
第 5 至 8 行 :获取本地缓存的注册的应用实例集合,实现代码如下:
第 10 至 26 行 :全量获取注册信息。
- 第 11 行 :配置
eureka.disableDelta = true
,禁用增量获取注册信息。默认值:false
。 - 第 12 行 :只获得一个
vipAddress
对应的应用实例们的注册信息。 - 第 13 行 :方法参数
forceFullRegistryFetch
强制全量获取注册信息。 - 第 14 至 15 行 :本地缓存为空。
- 第 25 至 26 行 :调用
#getAndStoreFullRegistry()
方法,全量获取注册信息,并设置到本地缓存。下文详细解析。
- 第 11 行 :配置
- 第 27 至 30 行 :增量获取注册信息,并刷新本地缓存,在 《Eureka 源码解析 —— 应用实例注册发现 (七)之增量获取》 详细解析。
- 第 31 至 32 行 :计算应用集合
hashcode
。该变量用于校验增量获取的注册信息和 Eureka-Server 全量的注册信息是否一致( 完整 ),在 《Eureka 源码解析 —— 应用实例注册发现 (七)之增量获取》 详细解析。 第 33 至 34 行 :打印调试日志,输出本地缓存的注册的应用实例数量。实现代码如下:
第 44 至 45 行 :触发 CacheRefreshedEvent 事件,事件监听器执行。目前 Eureka 未提供默认的该事件监听器。
#onCacheRefreshed()
方法,实现代码如下:- x
笔者的YY :你可以实现自定义的事件监听器监听 CacheRefreshedEvent 事件,以达到持久化最新的注册信息到存储器( 例如,本地文件 ),通过这样的方式,配合实现 BackupRegistry 接口读取存储器。BackupRegistry 接口调用如下:
第47 至 48 行 :更新本地缓存的当前应用实例在 Eureka-Server 的状态。
- 第 4 至 14 行 :从注册信息中获取当前应用在 Eureka-Server 的状态。
第 19 至 23 行 :对比本地缓存和最新的的当前应用实例在 Eureka-Server 的状态,若不同,更新本地缓存( 注意,只更新该缓存变量,不更新本地当前应用实例的状态(
instanceInfo.status
) ),触发 StatusChangeEvent 事件,事件监听器执行。目前 Eureka 未提供默认的该事件监听器。#onRemoteStatusChanged(...)
实现代码如下:- Eureka-Client 本地应用实例与 Eureka-Server 的该应用实例状态不同的原因,因为应用实例的覆盖状态,在 《Eureka 源码解析 —— 应用实例注册发现 (八)之覆盖状态》 有详细解析。
第 6 至 14 行 :全量获取注册信息,实现代码如下:
- 调用
AbstractJerseyEurekaHttpClient#getApplications(...)
方法,GET 请求 Eureka-Server 的apps/
接口,参数为regions
,返回格式为 JSON ,实现全量获取注册信息。
- 调用
第 16 至 24 行 :设置到本地注册信息缓存。
- 第 19 行 :TODO[0025] :并发更新的情况???
- 第 20 行 :调用
#filterAndShuffle(...)
方法,根据配置eureka.shouldFilterOnlyUpInstances = true
( 默认值 :true
) 过滤只保留状态为开启( UP )的应用实例,并随机打乱应用实例顺序。打乱后,实现调用应用服务的随机性。代码比较易懂,点击链接查看方法实现。
- 第 8 至 17 行 :TODO[0009]:RemoteRegionRegistry
- 第 19 至 25 行 :Eureka-Server 启动完成,但是未处于就绪( Ready )状态,不接受请求全量应用注册信息的请求,例如,Eureka-Server 启动时,未能从其他 Eureka-Server 集群的节点获取到应用注册信息。
第 27 至 28 行 :设置 API 版本号。默认最新 API 版本为 V2。实现代码如下:
第 30 至 36 行 :设置返回数据格式,默认 JSON 。
- 第 38 至 42 行 :创建响应缓存( ResponseCache ) 的键( KEY ),在 「3.2.1 缓存键」详细解析。
- 第 44 至 55 行 :从响应缓存读取全量注册信息,在 「3.3 缓存读取」详细解析。
其中,
#getVersionDelta()
和#getVersionDeltaWithRegions()
已经废弃。这里保留的原因主要是考虑兼容性。判断依据来自如下代码:#get()
:获得缓存。#getGZIP()
:获得缓存,并 GZIP 。#invalidate()
:过期缓存。- 只读缓存(
readOnlyCacheMap
) - 固定过期 + 固定大小的读写缓存(
readWriteCacheMap
) - 应用实例注册、下线、过期时,只只只过期
readWriteCacheMap
。 readWriteCacheMap
写入一段时间( 可配置 )后自动过期。- 定时任务对比
readWriteCacheMap
和readOnlyCacheMap
的缓存值,若不一致,以前者为主。通过这样的方式,实现了readOnlyCacheMap
的定时过期。 - 《为什么不应该使用ZooKeeper做服务发现》
- 《Spring Cloud Netflix Eureka源码导读与原理分析》「4. 作为服务注册中心,Eureka比Zookeeper好在哪里」
- 第 5 至 7 行 :调用
#get(key, useReadOnlyCache)
方法,读取缓存。其中shouldUseReadOnlyResponseCache
通过配置eureka.shouldUseReadOnlyResponseCache = true
(默认值 :true
) 开启只读缓存。如果你对数据的一致性有相对高的要求,可以关闭这个开关,当然因为少了readOnlyCacheMap
,性能会有一定的下降。 第 9 至 16 行 :调用
getValue(key, useReadOnlyCache)
方法,读取缓存。从readOnlyCacheMap
和readWriteCacheMap
变量可以看到缓存值的类为com.netflix.eureka.registry.ResponseCacheImpl.Value
,实现代码如下:第 21 至 31 行 :读取缓存。
- 第 21 至 28 行 :先读取
readOnlyCacheMap
。读取不到,读取readWriteCacheMap
,并设置到readOnlyCacheMap
。 - 第 29 至 31 行 :读取
readWriteCacheMap
。 readWriteCacheMap
实现代码如下:readWriteCacheMap
最大缓存数量为 1000 。- 调用
#generatePayload(key)
方法,生成缓存值。
- 第 21 至 28 行 :先读取
#generatePayload(key)
方法,实现代码如下:
- 第 10 至 12 行 :TODO[0009]:RemoteRegionRegistry
- 第 13 至 16 行 :调用
AbstractInstanceRegistry#getApplications()
方法,获得注册的应用集合。后调用#getPayLoad()
方法,将注册的应用集合转换成缓存值。�� 这两个方法代码较多,下面详细解析。 - 第 17 至 18 行 :获取增量注册信息的缓存值,在 《Eureka 源码解析 —— 应用实例注册发现 (七)之增量获取》 详细解析。
- 第 6 至 8 行 :TODO[0009]:RemoteRegionRegistry
第 9 至 16 行 :调用
#getApplicationsFromMultipleRegions(...)
方法,获得注册的应用集合,实现代码如下:- 第 2 至 第 10 行 :TODO[0009]:RemoteRegionRegistry
- 第 11 至 29 行 :获得获得注册的应用集合。
- 第 30 至 59 行 :TODO[0009]:RemoteRegionRegistry
- 第 61 行 :计算应用集合
hashcode
。该变量用于校验增量获取的注册信息和 Eureka-Server 全量的注册信息是否一致( 完整 ),在 《Eureka 源码解析 —— 应用实例注册发现 (七)之增量获取》 详细解析。
调用
#invalidate(keys)
方法,逐个过期每个缓存键值,实现代码如下:- 配置
eureka.responseCacheAutoExpirationInSeconds
,设置写入过期时长。默认值 :180 秒。 - 第 7 至 12 行 :初始化定时任务。配置
eureka.responseCacheUpdateIntervalMs
,设置任务执行频率,默认值 :30 * 1000 毫秒。 - 第 17 至 39 行 :创建定时任务。
- 第 22 行 :循环
readOnlyCacheMap
的缓存键。为什么不循环readWriteCacheMap
呢?readOnlyCacheMap
的缓存过期依赖readWriteCacheMap
,因此缓存键会更多。 - 第 28 行 至 33 行 :对比
readWriteCacheMap
和readOnlyCacheMap
的缓存值,若不一致,以前者为主。通过这样的方式,实现了readOnlyCacheMap
的定时过期。
- 第 22 行 :循环
1. 概述
本文主要分享 Eureka-Client 向 Eureka-Server 获取全量注册信息的过程。
FROM 《深度剖析服务发现组件Netflix Eureka》
Eureka-Client 获取注册信息,分成全量获取和增量获取。默认配置下,Eureka-Client 启动时,首先执行一次全量获取进行本地缓存注册信息,而后每 30 秒增量获取刷新本地缓存( 非“正常”情况下会是全量获取 )。
本文重点在于全量获取。
推荐 Spring Cloud 书籍:
2. Eureka-Client 发起全量获取
本小节调用关系如下:
2.1 初始化全量获取
Eureka-Client 启动时,首先执行一次全量获取进行本地缓存注册信息,首先代码如下:
2.2 定时获取
Eureka-Client 在初始化过程中,创建获取注册信息线程,固定间隔向 Eureka-Server 发起获取注册信息( fetch ),刷新本地注册信息缓存。实现代码如下:
2.3 刷新注册信息缓存
调用 #refreshRegistry(false)
方法,刷新注册信息缓存,实现代码如下:
2.4 发起获取注册信息
调用 #fetchRegistry(false)
方法,从 Eureka-Server 获取注册信息( 根据条件判断,可能是全量,也可能是增量 ),实现代码如下:
2.4.1 全量获取注册信息,并设置到本地缓存
调用 #getAndStoreFullRegistry()
方法,全量获取注册信息,并设置到本地缓存。下实现代码如下:
3. Eureka-Server 接收全量获取
3.1 接收全量获取请求
com.netflix.eureka.resources.ApplicationsResource
,处理所有应用的请求操作的 Resource ( Controller )。
接收全量获取请求,映射 ApplicationsResource#getContainers()
方法,实现代码如下:
3.2 响应缓存 ResponseCache
com.netflix.eureka.registry.ResponseCache
,响应缓存接口,接口代码如下:
3.2.1 缓存键
com.netflix.eureka.registry.Key
,缓存键。实现代码如下:
3.2.2 响应缓存实现类
com.netflix.eureka.registry.ResponseCacheImpl
,响应缓存实现类。
在 ResponseCacheImpl 里,将缓存拆分成两层 :
默认配置下,缓存读取策略如下:
缓存过期策略如下:
注意:应用实例注册、下线、过期时,不会很快刷新到 readWriteCacheMap
缓存里。默认配置下,最大延迟在 30 秒。
为什么可以使用缓存?
在 CAP 的选择上,Eureka 选择了 AP ,不同于 Zookeeper 选择了 CP 。
推荐阅读:
3.3 缓存读取
调用 ResponseCacheImpl#get(...)
方法( #getGzip(...)
类似 ),读取缓存,实现代码如下:
3.3.1 获得注册的应用集合
调用 AbstractInstanceRegistry#getApplications()
方法,获得注册的应用集合,实现代码如下:
3.3.2 转换成缓存值
调用 #getPayLoad()
方法,将注册的应用集合转换成缓存值,实现代码如下:
3.4 主动过期读写缓存
应用实例注册、下线、过期时,调用 ResponseCacheImpl#invalidate()
方法,主动过期读写缓存( readWriteCacheMap
),实现代码如下:
3.5 被动过期读写缓存
读写缓存( readWriteCacheMap
) 写入后,一段时间自动过期,实现代码如下:
3.6 定时刷新只读缓存
定时任务对比 readWriteCacheMap
和 readOnlyCacheMap
的缓存值,若不一致,以前者为主。通过这样的方式,实现了 readOnlyCacheMap
的定时过期。实现代码如下:
- Eureka 源码解析 —— 应用实例注册发现(六)之全量获取
- Eureka 源码解析 —— 应用实例注册发现(七)之增量获取
- Eureka 源码解析 —— 应用实例注册发现(一)之注册
- Eureka 源码解析 —— 应用实例注册发现(二)之续租
- Eureka 源码解析 —— 应用实例注册发现(三)之下线
- Eureka 源码解析 —— 应用实例注册发现(四)之自我保护机制
- Eureka 源码解析 —— 应用实例注册发现(五)之过期
- Eureka 源码解析 —— 应用实例注册发现(八)之覆盖状态
- Eureka 源码解析 —— Eureka源码解析 —— 应用实例注册发现 (九)之岁月是把萌萌的读写锁
- Spring-cloud & Netflix 源码解析:Eureka 服务注册发现接口 ****
- Eureka 源码解析 —— Eureka-Client 初始化(一)之 EurekaInstanceConfig
- Eureka 源码解析 —— Eureka-Client 初始化(二)之 EurekaClientConfig
- Eureka 源码解析 —— Eureka-Client 初始化(三)之 EurekaClient
- Eureka 源码解析 —— Eureka-Server 启动(一)之 ServerConfig
- Eureka 源码解析 —— Eureka-Server 启动(二)之 EurekaBootStrap
- spring could 之服务的注册与发现(Eureka)
- SpringCloud——Eureka服务注册和发现
- SpringCloud——Eureka服务注册和发现
- Apache Drill详解
- 简单LinuxC程序关于加密(将任意长字符转换为定长整数)
- 汉字转拼音 js工具类
- Spring事务传播机制
- 【zabbix】Windows服务器获取IIS站点以及程序池状态
- Eureka 源码解析 —— 应用实例注册发现(六)之全量获取
- Windows下的Composer安装
- Java 中 ThreadLocal 的使用解析
- IntelliJ IDEA整合SSM框架
- 整数相加求平均数
- highstate
- java判断json串是否有某个key值问题
- NLP 科研资料推荐
- Unity 3D 接入Facebook等多个第三方SDK -- 以Android平台为例。 --binbin 2017/12/14 一,软件版本 Unity 2017.2.0p3 (64-bit)