Spring Cloud Eureka源码解析之自我保护机制( 八)

在开发环境时,我们经常可以在eureka页面上看到这么一句红色的话
在这里插入图片描述
这就代表了触发了自我保护机制,eureka不会再剔除过期的服务。

默认情况下,当EurekaServer在一定时间内(默认90秒)没有接收到某个客户端实例的心跳,EurekaServer将会下线该实例。但是当网络分区故障发生或网络偶尔抖动时,客户端与EurekaServer之间无法正常通信,此时不应该下线实例。Eureka通过“自我保护机制”来解决这个问题:当EurekaServer短时间内丢失过多客户端时,这个节点就会进入自我保护模式。在自我保护模式下,EurekaServer不会剔除任何客户端。当网络故障恢复后,该节点会自动退出自我保护模式。

在上节服务剔除任务中evict方法中,有判断是否启用租约过期剔除
在这里插入图片描述
如果返回false,则表示禁用租约过期剔除,即触发了自我保护机制,直接return返回,不会去走接下来的服务剔除逻辑,那看下如何判断

@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;
}

首先判断是否启用了自我保护机制,如果没有启用自我保护机制,直接返回true,允许服务过期剔除。然后如果启用了(默认启用),就得判断每分钟续约阈值>0并且最近一分钟续约数>每分钟续约阈值,true表示目前整个环境正常,正常启用服务过期剔除,false表示最近的续约数没达到要求的阈值,过多的服务实例没法正常发送续约,此时就需要禁用服务过期剔除,也即启用自我保护机制,将这些服务保留在注册表中,保证其它服务可以正常调用到这些服务,等下次执行服务剔除任务时再次判断(默认60s)。
最近一分钟续约数根据实际续约次数得来,实际多少就多少,只跟续约操作有关。而每分钟续约阈值跟服务注册,服务下线,服务剔除都有关,甚至有一个定时任务每隔15分钟来计算该值。

服务注册

在这里插入图片描述
每当有一个实例注册上来时,会重新计算expectedNumberOfRenewsPerMin和numberOfRenewsPerMinThreshold,续约阈值=(期望续租数量+2)*0.85,这里硬编码了,因为默认续约周期是30s,一分钟就多两个续约数

服务下线和服务剔除

在这里插入图片描述
服务下线正好跟服务注册相反

更新续约阈值定时任务

在EurekaServer自动装配类中创建初始化EurekaServer上下文时会创建一个更新续约阈值的定时任务
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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;
                }
            }
        }
        // 计算续约阈值,默认就是注册数*2*0.85
        synchronized (lock) {
            // Update threshold only if the threshold is greater than the
            // current expected threshold of if the self preservation is disabled.
            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);
    }
}

该定时任务默认每隔15分钟执行一次,我在查资料时看到网上有人说自我保护机制是15分钟内心跳成功比例不大于85% 就触发自我保护机制,说的15分钟应该就是这里的15分钟。但是通过解析源码,这里的定时任务只是重新计算了numberOfRenewsPerMinThreshold值,并没有判断是否触发自我保护机制,这种说法并不准确。我的理解是是否触发自我保护机制就是在每次服务剔除任务执行时对numberOfRenewsPerMinThreshold和实际的续约数量判断
在这里插入图片描述
在这里插入图片描述
所以只要每隔60s时当最近一分钟实际的续约数量<=每分钟续约阈值时,就会禁用服务过期剔除,自然就是触发了自我保护机制,所以跟15分钟内的续约没有关系。当下次执行时最近一分钟实际的续约数量>每分钟续约阈值,就会自动恢复。

在开启服务剔除定时任务之前,对这两个参数进行了初始化
在这里插入图片描述
如果从其它节点没有复制到注册数,则count默认会为1,即单节点Eureka Server刚启动时每分钟期望的续约数就为2,每分钟续约阈值就为1,所以如果server启动后没有注册上来实例或注册的实例过少,过一会儿就会触发自我保护机制
默认情况下每次注册对应的numberOfRenewsPerMinThreshold:
在这里插入图片描述
所以默认情况下续约阈值numberOfRenewsPerMinThreshold=(2+2n)*0.85,只有注册数>=6时,才不会刚启动没多久就触发了自我保护机制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值