本文来说下Eureka自我保护机制

文章目录

  • 为什么要有自我保护机制
  • 重要变量
  • 变量更新
    • Eureka-Server初始化
    • cancle主动下线
    • 客户端注册
    • 定时器
  • 自我保护机制
    • 开启
    • 解除
  • 本文小结

为什么要有自我保护机制

众所周知,Eureka在CAP理论当中是属于AP , 也就说当产生网络分区时,Eureka保证系统的可用性,但不保证系统里面数据的一致性, 举个例子。

当发生网络分区的时候,Eureka-Server和client端的通信被终止,server端收不到大部分的client的续约,这个时候,如果直接将没有收到心跳的client端自动剔除,那么会将可用的client端剔除,这不符合AP理论,所以Eureka宁可保留也许已经宕机了的client端 , 也不愿意将可以用的client端一起剔除。 从这一点上,也就保证了Eureka程序的健壮性,符合AP理论。


重要变量

this.expectedNumberOfRenewsPerMin = count * 2;
this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());

expectedNumberOfRenewsPerMin :每分钟最大的续约数量,由于客户端是每30秒续约一次,一分钟就是续约2次, count代表的是客户端数量。

所以这个变量的计算公式 : 客户端数量*2

numberOfRenewsPerMinThreshold : 每分钟最小续约数量, 使用expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold()。
serverConfig.getRenewalPercentThreshold()的默认值为0.85 , 也就是说每分钟的续约数量要大于85% 。

Eureka的自我保护机制,都是围绕这两个变量来实现的, 如果每分钟的续约数量小于numberOfRenewsPerMinThreshold , 就会开启自动保护机制。

在此期间,不会再主动剔除任何一个客户端。


变量更新

Eureka-Server初始化,cancle主动下线, 客户端注册 ,定时器, 这四个场景会更新这两个变量。


Eureka-Server初始化

 protected void initEurekaServerContext() throws Exception {// ....省略N多代码// 服务刚刚启动的时候,去其他服务节点同步客户端的数量。int registryCount = this.registry.syncUp();// 这个方法里面计算expectedNumberOfRenewsPerMin的值this.registry.openForTraffic(this.applicationInfoManager, registryCount);// Register all monitoring statistics.EurekaMonitors.registerAllStats();}this.registry.openForTraffic(this.applicationInfoManager, registryCount);@Overridepublic void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {// 此处初始化值,客户端数量*2 this.expectedNumberOfRenewsPerMin = count * 2;// serverConfig.getRenewalPercentThreshold() 默认为0.85this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());// ...省略N多代码// 开启定时清理过期客户端的定时器super.postInit();
}

cancle主动下线

 @Overridepublic boolean cancel(final String appName, final String id,final boolean isReplication) {if (super.cancel(appName, id, isReplication)) {replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);synchronized (lock) {if (this.expectedNumberOfRenewsPerMin > 0) {// 重点在这里,,,,,主动下线的时候,需要去更新每分钟最大续约数,// 一个客户端的每30秒续约一次,一分钟就是续约两次,所以需要减2.this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin - 2;this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());}}return true;}return false;
}

客户端注册

public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {try {read.lock();// ....省略 N多代码if (existingLease != null && (existingLease.getHolder() != null)) {// ....省略 N多代码} else {synchronized (lock) {if (this.expectedNumberOfRenewsPerMin > 0) {// 重点在这里, 注册一个客户端,一个客户端每分钟需要两次续约,所以这里加2 this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin + 2;this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());}}logger.debug("No previous lease information found; it is new registration");}// ....省略 N多代码} finally {read.unlock();}
}

定时器

在Eureka-Server启动的时候,会进行初始化,执行路径如下:

DefaultEurekaServerContext 》@PostConstruct修饰的initialize()方法》init()

 @Overridepublic void init(PeerEurekaNodes peerEurekaNodes) throws Exception {// .... 省略N多代码// 启动定时器scheduleRenewalThresholdUpdateTask();// .... 省略N多代码}private void scheduleRenewalThresholdUpdateTask() {timer.schedule(new TimerTask() {@Overridepublic void run() {updateRenewalThreshold();}}, serverConfig.getRenewalThresholdUpdateIntervalMs(),serverConfig.getRenewalThresholdUpdateIntervalMs());}private void updateRenewalThreshold() {try {Applications apps = eurekaClient.getApplications();// 计算有效的应用实例数量int count = 0;for (Application app : apps.getRegisteredApplications()) {for (InstanceInfo instance : app.getInstances()) {if (this.isRegisterable(instance)) {++count;}}}synchronized (lock) {// 重新计算值if ((count * 2) > (serverConfig.getRenewalPercentThreshold() * numberOfRenewsPerMinThreshold)|| (!this.isSelfPreservationModeEnabled())) {this.expectedNumberOfRenewsPerMin = count * 2;this.numberOfRenewsPerMinThreshold = (int) ((count * 2) * serverConfig.getRenewalPercentThreshold());}}logger.info("Current renewal threshold is : {}", numberOfRenewsPerMinThreshold);} catch (Throwable e) {logger.error("Cannot update renewal threshold", e);}
}

renewalThresholdUpdateIntervalMs : 默认为15分钟serverConfig.getRenewalPercentThreshold() * numberOfRenewsPerMinThreshold 这个地方有个这个比较,当前最小续约数0.85 , 然后呢,count2 要大于他,这个意思,主要是为了防止开启自我保护机制之后,被定时器重新计算了expectedNumberOfRenewsPerMin 和numberOfRenewsPerMinThreshold 的值。


自我保护机制

一句话总结:某时刻某一个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存

  • 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了–因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制来解决这个问题–当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
  • 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着。
  • 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定。
  • 在SpringCloud中,可以使用eureka.server.enable-self-preservation=false禁用自我保护模式【不推荐关闭自我保护机制】

开启

定期清理任务的线程最终执行的是这个方法,这里就直接开始讲

public void evict(long additionalLeaseMs) {logger.debug("Running the evict task");// 是否需要开启自我保护机制,如果需要,那么直接RETURE, 不需要继续往下执行了if (!isLeaseExpirationEnabled()) {logger.debug("DS: lease expiration is currently disabled.");return;}// ..... 省略N多代码,。这下面主要是做服务自动下线的操作的}@Override
public boolean isLeaseExpirationEnabled() {// 是否开启自我保护机制,这是个配置,默认为trueif (!isSelfPreservationModeEnabled()) {return true;}// 计算是否需要自我保护return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
}

从上面可以导,判断是否开启自我保护机制,主要在于计算每分钟最小续约数的值, getNumOfRenewInLastMin()这个获取的是每分钟的续约数量(每个客户端来续约的时候,都是会更新这个值得,每分钟重置一次,有线程去跑的), 如果每分钟的续约数量>最小续约数,则不需要开启自我保护机制, 如果是小于,那么就是需要开启, 所以当返回false的时候,就需要开启自我保护机制了。

PS: 其实说白了,自我保护机制,就是在定时任务执行之前,判断每分钟的续约数量,然后决定是否继续执行下去。因此Eureka Server的过期时间(默认60s) ,客户端的续约时间(默认30s) , 这个配置最好不要更改,如果更改的话就会打破自我保护机制的规则。


解除

解除

  • 当服务的网络分区解除之后,客户端能够和服务进行交互时,在续约的时候,更新每分钟的续约数,当每分钟的续约数大于85%时,则自动解除。
  • 重启服务

本文小结

本文详细介绍了Eureka自我保护机制。

Eureka自我保护机制相关推荐

  1. eureka自我保护时间_Spring Cloud Eureka 自我保护机制

    自我保护出现 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行. 默认情况下,如果Eureka Serve ...

  2. Spring Cloud Eureka 自我保护机制

    Spring Cloud Eureka 自我保护机制 Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这 ...

  3. eureka自我保护时间_SpringCloud Eureka自我保护机制

    自我保护背景 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行. 默认情况下,如果Eureka Serve ...

  4. SpringCloud Eureka自我保护机制

    转载自 SpringCloud Eureka自我保护机制 自我保护背景 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他 ...

  5. SpringCloud Eureka自我保护机制介绍及配置

    概述:谈到Eureka的自我保护机制时,我们需要知道其中一些客户端和服务端的概念.比如客户端的心跳发送时间间隔.服务续约时间:服务端的服务剔除时间间隔.阈值更新时间间隔. 客户端心跳发送时间间隔(eu ...

  6. eureka:自我保护机制_对自我怀疑的开发人员:您足够好吗?

    eureka:自我保护机制 by Sihui Huang 黄思慧 对自我怀疑的开发人员:您足够好吗? (To self-doubting developers: are you good enough ...

  7. Spring Cloud Eureka 自我保护机制(EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY)

    在本地启动一个Euraka-Server服务(服务注册中心)和一个Euraka-Client服务(服务注册者-应用服务)两个服务.过了一会儿后,在Euraka-Server界面显示:EMERGENCY ...

  8. 天荒地老修仙功-第六部第二篇:Spring Cloud Eureka自我保护机制

    Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,但是在保护期内如果 ...

  9. 深入理解Eureka 自我保护机制(五)

    对自我保护的理解: 自我保护的作用是保证服务的稳定性,也就是怕过多的服务心跳失败,是Eureka服务端的问题,而不是客户端的问题,所以为了避免将正常的服务剔除,所以加了保护机制,当然保护机制的话也有可 ...

最新文章

  1. 二叉树的前序,中序,后序的递归、迭代实现
  2. 循环map_python函数 map函数—比for还好用的循环
  3. 转帖:3D音频之双耳效应
  4. 关于printf()与自增自减运算符结和问题
  5. 二叉树题目----2 检查两颗树是否相同 和 对称二叉树的判定
  6. 调试利器:浏览器 Logger
  7. android studio 安装问题,解决Android Studio的安装问题
  8. c语言变量定义数组,C语言中数组的定义和使用
  9. SNMP简单网络管理协议
  10. android手机禁止休眠_浮窗----手机是否可以一心多用?这个只是开始而已。
  11. 面试机器学习、数据挖掘、大数据岗位时遇到的各种问题
  12. python获取磁盘剩余空间的方法
  13. 如何使用secureCRT连接vmware中的虚拟主机?
  14. 天梯 L1 Practic1 题解合集
  15. L2-029 特立独行的幸福 (递归) 有代码详细解析
  16. 大家都在努力,你凭什么不努力?
  17. window系统下添加路由的方法
  18. 如何写系统需求分析书
  19. 神经网络隐含层节点数
  20. Scratch案例—在Scratch上制作植物大战僵尸游戏

热门文章

  1. 甲骨文就 Java 安全问题与 FTC 达成和解
  2. 中小企业集群ntpd服务搭建
  3. OGEngine引擎开发slot 手游强势来袭
  4. MongoDB 副本集的相关概念【转】
  5. javascript中call和apply的区别
  6. IronPython系列:Observer Pattern及其实现
  7. CKEditor的使用-编辑文本
  8. cacti安装和配置 技术交流群:146510248
  9. 推荐8个最佳的jQuery移动开发插件
  10. Google啊谷狗,你是在考验中国人的智商还是探测中国人的情商?