Spring Cloud Eureka原理分析(二):续租、下线、自我保护机制和自动清理(服务端)

栏目: Java · 发布时间: 5年前

内容简介:续租、下线等操作比较直观,实际上也不复杂。让我们自己想想它们大概会在服务端有什么操作。—— 服务端确实做了差不多这些事情。因此为了不影响其他重要事件,这里不再继续深入。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页面上面经常会见到这个警告,就是启用了自我保护机制。

Spring Cloud Eureka原理分析(二):续租、下线、自我保护机制和自动清理(服务端)

关于这个问题网上的解释也很多了,下面这篇文章提供了几幅有用的图:

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. 计算时机

有四个地方会重新计算 numberOfRenewsPerMinThresholdexpectedNumberOfRenewsPerMin

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) 又比较长,下面分段分析。

  1. 判断是不是启用了自我保护机制,如是则不再清理。
  2. 遍历registry中的所有实例,比较当前时间和 lastUpdatedTime + duration + compensationTime ,如果前者大,说明已过期。
  3. 计算最大可清理的实例数量。不得让清理后的实例数量低于当前数量 * eureka.server.renewalPercentThreshold ,默认又是0.85。这个阈值还是很高的,如果有大量实例过期,就需要分多批执行才能清理完。
  4. 随机清理过期的租约。由于租约是按照应用顺序添加到数组,通过随机的方式,尽量避免单个应用被全部过期。
  5. 最后,调用 internalCancel 处理每个要被清理的lease,这个方法就是前面的cancel阶段会调的。

这个自动清理似乎没有告知同伴节点,大家各做各的。可见Eureka的一致性是蛮低的。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人类思维如何与互联网共同进化

人类思维如何与互联网共同进化

[美] 约翰·布罗克曼 / 付晓光 / 浙江人民出版社 / 2017-3 / 79.90元

➢人类是否因互联网的诞生进入了公平竞争的场域? “黑天鹅事件”频频发生,我们的预测能力是否正在退化? 智人的第四阶段有哪些特征? 全球脑会使人类成为“超级英雄”吗? 虚拟现实技术会不会灭绝人类的真实体验? 还有更多不可预知答案的问题,你将在本书中找到属于自己的答案! ➢ 我们的心智正和互联网发生着永无止境的共振,人类思维会因此产生怎样的进化效应?本书编者约翰•布......一起来看看 《人类思维如何与互联网共同进化》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具