Eureka 源码解析 —— 应用实例注册发现(八)之覆盖状态
来源:互联网 发布:数控编程仿真软件 编辑:程序博客网 时间:2024/05/16 16:08
摘要: 原创出处 http://www.iocoder.cn/Eureka/instance-registry-override-status/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文主要基于 Eureka 1.8.X 版本
- 1. 概述
- 2. 应用实例覆盖状态变更接口
- 2.1 更新应用实例覆盖状态
- 3. 应用实例覆盖状态删除接口
- 3.1 删除应用实例覆盖状态
- 4. 应用实例覆盖状态映射
- 4.1 应用实例状态覆盖规则
- 4.2 注册场景
- 4.3 续租场景
- 4.4 下线场景
- 4.5 过期场景
- 请支持正版。下载盗版,等于主动编写低级 BUG 。
- 程序猿DD —— 《Spring Cloud微服务实战》
- 周立 —— 《Spring Cloud与Docker微服务架构实战》
- 两书齐买,京东包邮。
- PUT
apps/${APP_NAME}/${INSTANCE_ID}/status
- DELETE
apps/${APP_NAME}/${INSTANCE_ID}/status
调用
PeerAwareInstanceRegistryImpl#statusUpdate(...)
方法,更新应用实例覆盖状态。实现代码如下:- 调用父类
AbstractInstanceRegistry#statusUpdate(...)
方法,更新应用实例覆盖状态。
- 调用父类
- 第 6 至 7 行 :获取读锁。在 《Eureka源码解析 —— 应用实例注册发现 (九)之岁月是把萌萌的读写锁》 详细解析。
- 第 8 至 9 行 :添加覆盖状态变更次数到监控。配合 Netflix Servo 实现监控信息采集。
- 第 10 至 15 行 :获得租约。
- 第 16 至 18 行 :租约不存在,返回更新失败。
- 第 20 至 21 行 :设置租约最后更新时间( 续租 )。
- 第 23 至 29 行 :持有租约的应用实例不存在,理论来说不会出现,防御性编程。
- 第 31 行 :应用实例当前状态和覆该状态不一致时才更新覆盖状态。
- 第 32 至 36 行 :当覆盖状态是
InstanceStatus.UP
,设置租约的开始服务的时间戳(只有第一次有效)。 第 37 至 39 行 :添加到应用实例覆盖状态映射(
overriddenInstanceStatusMap
)。此处英文"NAC"
可能是"Network Access Control"
的缩写,感兴趣的可以看看 《Network Access Control》 。overriddenInstanceStatusMap
属性代码如下:- 有效期 1 小时。每次访问后会刷新有效期,在后文你会看到对其的访问。
第 40 至 43 行 :设置应用实例的覆盖状态。用于 Eureka-Server 集群同步。
- 第 46 至 47 行 :设置应用实例状态。设置后,Eureka-Client 拉取注册信息,被更新覆盖状态的应用实例就是设置的状态。
- 第 48 至 55 行 :设置应用实例的数据不一致时间。用于 Eureka-Server 集群同步。
- 第 56 至 58 行 :添加应用实例到最近租约变更记录队列。
- 第 59 至 60 行 :设置应用实例的最后更新时间(
lastUpdatedTimestamp
)。lastUpdatedTimestamp
主要用于记录最后更新时间,无实际业务用途。 - 第 61 至 62 行 :设置响应缓存过期。
- 第 64 行 :返回更新成功。
- 第 68 行 :释放读锁。
- 请求参数
newStatusValue
,设置应用实例的状态。大多数情况下,newStatusValue
要和应用实例实际的状态一致,因为该应用实例的 Eureka-Client 不会从 Eureka-Server 拉取到该应用状态newStatusValue
。另外一种方式,不传递该参数,相当于UNKNOWN
状态,这样,Eureka-Client 会主动向 Eureka-Server 再次发起注册,具体原因在 [「4.3 续租场景」] 详细解析,更加推荐的方式。 调用父类
AbstractInstanceRegistry#deleteStatusOverride(...)
方法,删除应用实例覆盖状态。实现代码如下:- 调用父类
AbstractInstanceRegistry#deleteStatusOverride(...)
方法,删除应用实例覆盖状态。
- 调用父类
- 第 7 至 8 行 :获取读锁。在 《Eureka源码解析 —— 应用实例注册发现 (九)之岁月是把萌萌的读写锁》 详细解析。
- 第 9 至 10 行 :添加覆盖状态删除次数到监控。配合 Netflix Servo 实现监控信息采集。
- 第 11 至 16 行 :获得租约。
- 第 17 至 19 行 :租约不存在,返回更新失败。
- 第 21 至 22 行 :设置租约最后更新时间( 续租 )。
- 第 24 至 30 行 :持有租约的应用实例不存在,理论来说不会出现,防御性编程。
- 第 32 至 33 行 :移除出应用实例覆盖状态映射(
overriddenInstanceStatusMap
)。 - 第 34 行 :应用实例的覆盖状态存在才设置状态。
- 第 35 至 36 行 :设置应用实例的覆盖状态为 InstanceStatus.UNKNOWN。用于 Eureka-Server 集群同步。
- 第 37 至 38 行 :设置应用实例的状态为
newStatus
。设置后,Eureka-Client 拉取注册信息,被更新覆盖状态的应用实例就是设置的状态。 - 第 39 至 48 行 :设置应用实例的数据不一致时间。用于 Eureka-Server 集群同步。
- 第 49 至 51 行 :添加应用实例到最近租约变更记录队列。
- 第 52 至 53 行 :设置应用实例的最后更新时间(
lastUpdatedTimestamp
)。lastUpdatedTimestamp
主要用于记录最后更新时间,无实际业务用途。 - 第 54 至 55 行 :设置响应缓存过期。
- 第 57 行 :返回更新成功。
- 第 61 行 :释放读锁。
调用
#getInstanceInfoOverrideRule()
方法,获取应用实例状态覆盖规则( InstanceStatusOverrideRule )。在 PeerAwareInstanceRegistryImpl 里该方法实现代码如下:#apply(...)
方法参数instanceInfo
代表的是关注状态的应用实例,和方法参数existingLease
里的应用实例不一定是同一个,在 「4.1.6 总结」 详细解析。com.netflix.eureka.registry.rule.StatusOverrideResult
,状态覆盖结果。当匹配成功,返回matches = true
;否则,返回matches = false
。- AsgEnabledRule ,亚马逊 AWS 专用,跳过。
rules
属性,复合规则集合。在 PeerAwareInstanceRegistryImpl 里,我们可以看到该属性为 [ DownOrStartingRule , OverrideExistsRule , LeaseExistsRule ] 。defaultRule
属性,默认规则,值为 AlwaysMatchInstanceStatusRule 。#apply()
方法,优先使用复合规则(rules
),顺序匹配,直到匹配成功 。当未匹配成功,使用默认规则(defaultRule
) 。- 注意,使用的是
instanceInfo
。 statusOverrides
属性,应用实例覆盖状态映射。在 PeerAwareInstanceRegistryImpl 里,使用AbstractInstanceRegistry.overriddenInstanceStatusMap
属性赋值。- 上文我们提到
AbstractInstanceRegistry.overriddenInstanceStatusMap
每次访问刷新有效期,如果调用到 OverrideExistsRule ,则会不断刷新。从 DownOrStartingRule 看到,instanceInfo
处于InstanceInfo.InstanceStatus.DOWN
或者InstanceInfo.InstanceStatus.STARTING
才不会继续调用 OverrideExistsRule 匹配,AbstractInstanceRegistry.overriddenInstanceStatusMap
才有可能过期。 - 注意,使用的是
existingLease
,并且非 Eureka-Server 请求。 - 注意,使用的是
instanceInfo
。 - 应用实例状态是最重要的属性,没有之一,因而在最终实例状态的计算,以可信赖为主。
- DownOrStartingRule ,
instanceInfo
处于STARTING
或者DOWN
状态,应用实例可能不适合提供服务( 被请求 ),考虑可信赖,返回instanceInfo
的状态。 - OverrideExistsRule ,当存在覆盖状态(
statusoverrides
) ,使用该状态,比较好理解。 - LeaseExistsRule ,来自 Eureka-Client 的请求( 非 Eureka-Server 集群请求),当 Eureka-Server 的实例状态存在,并且处于
UP
或则OUT_OF_SERVICE
,保留当前状态。原因,禁止 Eureka-Client 主动在这两个状态之间切换。如果要切换,使用应用实例覆盖状态变更与删除接口。 - AlwaysMatchInstanceStatusRule ,使用
instanceInfo
的状态返回,以保证能匹配到状态。 - 在下文中,你会看到,
#getOverriddenInstanceStatus()
方法会在注册和续租使用到。结合上图,我们在 「4.2 注册场景」 和 「4.3 续租场景」 也会详细解析。 - 在下文中,你会看到,
#getOverriddenInstanceStatus()
方法会在注册和续租使用到,方法参数instanceInfo
情况如下:- 注册时 :请求参数
instanceInfo
,和existingLease
的应用实例属性不相等( 如果考虑 Eureka-Server 的LastDirtyTimestamp
更大的情况,则类似 续租时的情况 ) 。 - 续租时 :使用 Eureka-Server 的
existingLease
的应用实例,两者相等。 - 总的来说,可以将
instanceInfo
理解成请求方的状态。
- 注册时 :请求参数
- DownOrStartingRule ,
- 第 7 行 :获得已存在的租约(
existingLease
) 。 - 第 15 行 :创建新的租约(
lease
)。 - 第 24 至 28 行 :设置应用实例的覆盖状态(
overridestatus
),避免注册应用实例后,丢失覆盖状态。 - 第 30 至 32 行 :获得应用实例最终状态。注意下,不考虑第 9 行代码的情况,
registrant
和existingLease
的应用实例不是同一个对象。 - 第 33 只 34 行 :设置应用实例的状态。
- 第 15 至 17 行 :获得应用实例的最终状态。
- 第 18 至 24 行 :应用实例的最终状态为
UNKNOWN
,无法续约 。返回false
后,请求方( Eureka-Client 或者 Eureka-Server 集群其他节点 )会发起注册,在 《Eureka 源码解析 —— 应用实例注册发现(二)之续租》 有详细解析。为什么会是UNKNOWN
呢?在 「3. 应用实例覆盖状态删除接口」 传递应用实例状态为UNKNOWN
。 - 第 25 至 36 行 :应用实例的状态与最终状态不相等,使用最终状态覆盖应用实例的状态。为什么会不相等呢?
#renew(...)
和#statusUpdate(...)
可以无锁,并行执行,如果#renew(...)
执行完第 16 行代码,获取到overriddenInstanceStatus
后,恰巧#statusUpdate(...)
执行完更新应用实例状态newStatus
,又恰好两者不相等,使用overriddenInstanceStatus
覆盖掉应用实例的newStatus
状态。- 那岂不是覆盖状态(
overriddenstatus
)反倒被覆盖???不会,在下一次心跳,应用实例的状态会被修正回来。当然,如果应用实例状态如果为UP
或者STARTING
不会被修正,也不应该被修正。
AbstractJerseyEurekaHttpClient#statusUpdate(...)
AbstractJerseyEurekaHttpClient#deleteStatusOverride(...)
1. 概述
本文主要分享 应用实例的覆盖状态属性。
这里要注意下,不是应用实例的状态( status
),而是覆盖状态( overridestatus
) 。代码如下:
调用 Eureka-Server HTTP Restful 接口 apps/${APP_NAME}/${INSTANCE_ID}/status
对应用实例覆盖状态的变更,从而达到主动的、强制的变更应用实例状态。注意,实际不会真的修改 Eureka-Client 应用实例的状态,而是修改在 Eureka-Server 注册的应用实例的状态。
通过这样的方式,Eureka-Client 在获取到注册信息时,并且配置 eureka.shouldFilterOnlyUpInstances = true
,过滤掉非 InstanceStatus.UP
的应用实例,从而避免调动该实例,以达到应用实例的暂停服务( InstanceStatus.OUT_OF_SERVICE
),而无需关闭应用实例。
因此,大多数情况下,调用该接口的目的,将应用实例状态在 ( InstanceStatus.UP
) 和 ( InstanceStatus.OUT_OF_SERVICE
) 之间切换。引用官方代码上的注释如下:
AbstractInstanceRegistry#statusUpdate
方法注释
Updates the status of an instance.
Normally happens to put an instance between {@link InstanceStatus#OUT_OF_SERVICE} and {@link InstanceStatus#UP} to put the instance in and out of traffic.
推荐 Spring Cloud 书籍:
接口 apps/${APP_NAME}/${INSTANCE_ID}/status
实际是两个:
下面,我们逐节分享这两接口的代码实现。
2. 应用实例覆盖状态变更接口
应用实例覆盖状态变更接口,映射 InstanceResource#statusUpdate()
方法,实现代码如下:
2.1 更新应用实例覆盖状态
调用 AbstractInstanceRegistry#statusUpdate(...)
方法,更新应用实例覆盖状态,实现代码如下:
3. 应用实例覆盖状态删除接口
当我们不需要应用实例的覆盖状态时,调度接口接口进行删除。关联官方 issue#89
:Provide an API to remove all overridden status。
应用实例覆盖状态删除接口,映射 InstanceResource#deleteStatusUpdate()
方法,实现代码如下:
3.1 删除应用实例覆盖状态
调用父类 AbstractInstanceRegistry#deleteStatusOverride(...)
方法,删除应用实例覆盖状态。实现代码如下:
4. 应用实例覆盖状态映射
虽然我们在上面代码,使用覆盖状态( overridestatus
)设置到应用实例的状态( status
),实际调用 AbstractInstanceRegistry#getOverriddenInstanceStatus(...)
方法,根据应用实例状态覆盖规则( InstanceStatusOverrideRule )进行计算最终应用实例的状态。实现代码如下:
4.1 应用实例状态覆盖规则
com.netflix.eureka.registry.rule.InstanceStatusOverrideRule
,应用实例状态覆盖规则接口。接口代码如下:
实现类关系如下:
4.1.1 FirstMatchWinsCompositeRule
com.netflix.eureka.registry.rule.FirstMatchWinsCompositeRule
,复合规则,以第一个匹配成功为准。实现代码如下:
4.1.2 DownOrStartingRule
com.netflix.eureka.registry.rule.DownOrStartingRule
,匹配 InstanceInfo.InstanceStatus.DOWN
或者 InstanceInfo.InstanceStatus.STARTING
状态。实现 #apply(...)
代码如下:
4.1.3 OverrideExistsRule
com.netflix.eureka.registry.rule.OverrideExistsRule
,匹配应用实例覆盖状态映射( statusOverrides
) 。实现 #apply(...)
代码如下:
4.1.4 LeaseExistsRule
com.netflix.eureka.registry.rule.LeaseExistsRule
,匹配已存在租约的应用实例的 nstanceStatus.OUT_OF_SERVICE
或者 InstanceInfo.InstanceStatus.UP
状态。实现 #apply(...)
代码如下:
4.1.5 AlwaysMatchInstanceStatusRule
com.netflix.eureka.registry.rule.AlwaysMatchInstanceStatusRule
,总是匹配关注状态的实例对象( instanceInfo
)的状态。实现 #apply(...)
代码如下:
4.1.6 总结
我们将 PeerAwareInstanceRegistryImpl 的应用实例覆盖状态规则梳理如下:
4.2 注册场景
4.3 续租场景
4.4 下线场景
4.5 过期场景
同 「4.4 下线场景」 相同。
5. 客户端调用接口
对应用实例覆盖状态的变更和删除接口调用,点击如下方法查看,非常易懂,本文就不啰嗦了:
- 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服务注册和发现
- Unity3D 鼠标拖动和旋转物体以及鼠标拖动图片
- HTML中      等6种空白空格实体的区别
- 【解决】:不能删除旧版本的Apple Software Update
- HTTP和FTP的区别的一些理论知识
- Cocos2d-x内存管理之autorelease,addChild和removeFromParent
- Eureka 源码解析 —— 应用实例注册发现(八)之覆盖状态
- Python checkio "Making Change"解决方案
- HDU6227(2017acm-沈阳) 贪心/思维/瞎搞
- 01_张孝祥_Java多线程_传统线程技术回顾
- 雷电重磅合作不断,百亿市值可期!
- 印度税务调查员突袭比特币交易所
- WEBRTC- 拉取代码及编译
- 美国专利商标局审批通过美国银行加密货币交易所专利
- 韩国对比特币交易采取新的限制措施