内容简介:续租、下线等操作比较直观,实际上也不复杂。让我们自己想想它们大概会在服务端有什么操作。—— 服务端确实做了差不多这些事情。因此为了不影响其他重要事件,这里不再继续深入。Eureka选择做一个支持AP的系统(CAP定理)。其实很好理解,当发生大量应用实例不再renew时,服务端认为发生了网络分区。Eureka为了保证高可用,不再踢掉已经到期的lease,从而让依赖于该服务端实例的client端仍然能正常进行服务发现(尽管存在服务实例确实挂掉的可能,即牺牲了一致性)。
续租、下线等操作比较直观,实际上也不复杂。让我们自己想想它们大概会在服务端有什么操作。
- renew: 更新Lease的
lastUpdateTimestamp
, 更新一下InstanceInfo的最新状态。然后调用其他同伴节点的renew接口。 - cancel:把lease从registry中移除,设置lease的
evictionTimestamp
,然后设置InstanceInfo为已删除。然后把lease加入到recentlyChangedQueue
中。最后调用同伴节点的cancel接口。
—— 服务端确实做了差不多这些事情。因此为了不影响其他重要事件,这里不再继续深入。
自我保护机制
Eureka选择做一个支持AP的系统(CAP定理)。其实很好理解,当发生大量应用实例不再renew时,服务端认为发生了网络分区。Eureka为了保证高可用,不再踢掉已经到期的lease,从而让依赖于该服务端实例的client端仍然能正常进行服务发现(尽管存在服务实例确实挂掉的可能,即牺牲了一致性)。
在Spring Cloud Eureka的Home页面上面经常会见到这个警告,就是启用了自我保护机制。
关于这个问题网上的解释也很多了,下面这篇文章提供了几幅有用的图:
The Mystery of Eureka Self-Preservation
实现细节
这篇文章有所有你想要的。 Eureka 源码解析 —— 应用实例注册发现(四)之自我保护机制
搬过来一些重点:
1. 触发条件
看代码
// PeerAwareInstanceRegistryImpl.java @Override public boolean isLeaseExpirationEnabled() { if (!isSelfPreservationModeEnabled()) { // The self preservation mode is disabled, hence allowing the instances to expire. return true; } return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold; } 复制代码
当每分钟心跳次数( renewsLastMin
) 小于 numberOfRenewsPerMinThreshold
时,并且开启自动保护模式开关( eureka.server.enableSelfPreservation = true
) 时,触发自动保护机制,不再自动过期租约。
其中:
2. 计算公式
-
numberOfRenewsPerMinThreshold
=expectedNumberOfRenewsPerMin
* 续租百分比(eureka.server.renewalPercentThreshold
, 默认0.85 ) -
expectedNumberOfRenewsPerMin
= 当前注册的应用实例数 x 2
为什么乘以 2:
默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2 。
这里有硬编码的情况,因此修改应用实例的续租频率会让计算不太准。不过,自我保护机制我比较怀疑它的重要性,该调还得调。
3. 计算时机
有四个地方会重新计算 numberOfRenewsPerMinThreshold
、 expectedNumberOfRenewsPerMin
。
eureka.server.renewalThresholdUpdateIntervalMs
自动清理机制
清理过期lease的也是一个定时任务 EvictionTask
,频率由 eureka.server.evictionIntervalTimerInMs
,默认为60秒。
1. EvictionTask
代码
class EvictionTask extends TimerTask { @Override public void run() { try { // 获取 补偿时间毫秒数 long compensationTimeMs = getCompensationTimeMs(); logger.info("Running the evict task with compensationTime {}ms", compensationTimeMs); // 清理过期租约逻辑 evict(compensationTimeMs); } catch (Throwable e) { logger.error("Could not run the evict task", e); } } } 复制代码
那个 getCompensationTimeMs()
方法的意思是,定时器可能比设定的时间更晚触发,原因可能是GC等。假设本来要在上一次执行后60s再次触发,但因为GC在第70秒才被触发,这时去检查有没有lease有没有超期无renew不能用70s来算,而应该还用60s来算,因为在这10s的GC时间中,很可能此服务端无法处理注册请求。补偿的10s就是这个意思,就是允许实例多超期这10s。
2. 清理逻辑
evict(compensationTime)
又比较长,下面分段分析。
- 判断是不是启用了自我保护机制,如是则不再清理。
- 遍历registry中的所有实例,比较当前时间和
lastUpdatedTime
+duration
+compensationTime
,如果前者大,说明已过期。 - 计算最大可清理的实例数量。不得让清理后的实例数量低于当前数量 *
eureka.server.renewalPercentThreshold
,默认又是0.85。这个阈值还是很高的,如果有大量实例过期,就需要分多批执行才能清理完。 - 随机清理过期的租约。由于租约是按照应用顺序添加到数组,通过随机的方式,尽量避免单个应用被全部过期。
- 最后,调用
internalCancel
处理每个要被清理的lease,这个方法就是前面的cancel阶段会调的。
这个自动清理似乎没有告知同伴节点,大家各做各的。可见Eureka的一致性是蛮低的。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 面试官:你知道 Dubbo 怎么做优雅上下线的吗?你:优雅上下线是啥?
- SpringCloud服务的平滑上下线
- SpringCloud服务的平滑上下线
- Eureka 源码剖析(五):服务下线
- Elasticsearch 平滑下线节点实践指南
- Elasticsearch 平滑下线节点实践指南
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Probability and Computing
Michael Mitzenmacher、Eli Upfal / Cambridge University Press / 2005-01-31 / USD 66.00
Assuming only an elementary background in discrete mathematics, this textbook is an excellent introduction to the probabilistic techniques and paradigms used in the development of probabilistic algori......一起来看看 《Probability and Computing》 这本书的介绍吧!