Spring中Eureka的自我保护详解

 更新时间:2023年11月21日 09:39:05   作者:dalianpai  
这篇文章主要介绍了Spring中Eureka的自我保护详解,当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式,一旦进入该模式,Eureka Server就会保护服务注册表中的信息,需要的朋友可以参考下

Eureka的自我保护

当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

如果想研究自我保护机制,那就要从服务下线那里,因为自我保护来决定是让eureka进行剔除服务的,下线代码如下:

public void evict(long additionalLeaseMs) {
        logger.debug("Running the evict task");
 
        //是否允许主动摘除故障的服务实例
        if (!isLeaseExpirationEnabled()) {
            logger.debug("DS: lease expiration is currently disabled.");
            return;
        }
 
       ....
 }
@Override
    public boolean isLeaseExpirationEnabled() {
        //默认是true,关闭自我保护机制的话,这个方法永远返回true,随时都可以清除故障的服务实例。
        if (!isSelfPreservationModeEnabled()) {
            // The self preservation mode is disabled, hence allowing the instances to expire.
            return true;
        }
        //numberOfRenewsPerMinThreshold  这个是我期望的一分钟发送多少心跳。
        //getNumOfRenewsInLastMin 这个是上一分钟一共发来多少心跳
        return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
    }

触发的机制就是说,如果最近一分钟发过来的心跳小于期望的值,这进入心跳保护机制。那么就来看一下,这个期望的值是什么算出来的。

首先在初始化的时候,就会给他先赋值,默认值为其他server拉着的注册表信息的数量乘以2

// EurekaBootStrap.java
protected void initEurekaServerContext() throws Exception {
 
    // ... 省略其它代码
 
    // 【2.2.10】从其他 Eureka-Server 拉取注册信息
    // Copy registry from neighboring eureka node
    int registryCount = registry.syncUp();
    registry.openForTraffic(applicationInfoManager, registryCount);
    
    // ... 省略其它代码
}
 
// PeerAwareInstanceRegistryImpl.java
@Override
public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
   // Renewals happen every 30 seconds and for a minute it should be a factor of 2.
   this.expectedNumberOfRenewsPerMin = count * 2;
   this.numberOfRenewsPerMinThreshold =
           (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());

然后再上线,下线,故障的时候都会对他进行修改。

image-20211011213620374

由于以前的版本为硬编码,是直接乘以2的,近期的版本,对代码进行了优化,因为心跳是30秒发来一次,所以直接用60/30,然后在乘以0.85。

为什么乘以续租百分比

低于这个百分比,意味着开启自我保护机制。默情况下,eureka.renewalPercentThreshold = 0.85 。

如果你真的调整了续租频率,可以等比去续租百分比,以保证合适的触发自我保护机制的阀值。另外,你需要注意,续租频率是 Client 级别,续租百分比是 Server 级别。

protected void updateRenewsPerMinThreshold() {
        this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews
                * (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds())
                * serverConfig.getRenewalPercentThreshold());
    }

以前的代码是有bug的,只对下线的代码进行了修改,故障是没有的,近期版本也做了修复。把剔除服务的相关代码都抽取了出来了,形成了internalCancel方法,被下面的2个方法调用,在它的方法里,做了减法。

image-20211011213851595

image-20211011214105920

定时更新

Eureka-Server 时重新计算 numberOfRenewsPerMinThreshold 、expectedNumberOfRenewsPerMin 。

实现代码如下:

// PeerAwareInstanceRegistryImpl.java
private void scheduleRenewalThresholdUpdateTask() {
   timer.schedule(new TimerTask() {
                      @Override
                      public void run() {
                          updateRenewalThreshold();
                      }
                  }, serverConfig.getRenewalThresholdUpdateIntervalMs(),
           serverConfig.getRenewalThresholdUpdateIntervalMs());
}
 
// AbstractInstanceRegistry.java
/**
* 自我保护机锁
*
* 当计算如下参数时使用:
*  1. {@link #numberOfRenewsPerMinThreshold}
*  2. {@link #expectedNumberOfRenewsPerMin}
*/
protected final Object lock = new Object();
 
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;
               }
           }
       }
       // 计算 expectedNumberOfRenewsPerMin 、 numberOfRenewsPerMinThreshold 参数
       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);
   }
}

Registry注册表,默认是15分钟,会跑一次定时任务,算一下服务实例的数量,如果从别的eureka server拉取到的服务实例的数量,大于当前的服务实例的数量,会重新计算一下,主要是跟其他的eureka server做一下同步

到此这篇关于Spring中Eureka的自我保护详解的文章就介绍到这了,更多相关Eureka的自我保护内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring MVC环境中文件上传功能的实现方法详解

    Spring MVC环境中文件上传功能的实现方法详解

    文件上传是大家应该都不陌生的一个功能,最近在开发中就又遇到了这个需求,所以想着总结一下方便以后需要的时候参考,下面这篇文章主要给大家介绍了关于Spring MVC环境中文件上传功能的实现方法,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-10-10
  • MyBatis图文并茂讲解注解开发一对一查询

    MyBatis图文并茂讲解注解开发一对一查询

    这篇文章主要介绍了SpringBoot中Mybatis注解一对一查询的实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 基于Java Socket实现一个简易在线聊天功能(一)

    基于Java Socket实现一个简易在线聊天功能(一)

    这篇文章主要给大家介绍基于Java Socket实现一个简易在线聊天功能(一),分为客户端和服务端两段代码,非常具有参考价值,感兴趣的朋友一起学习吧
    2016-05-05
  • 掌握SpringMVC中@InitBinder的实际应用

    掌握SpringMVC中@InitBinder的实际应用

    这篇文章主要介绍了掌握SpringMVC中@InitBinder的实际应用,@InitBinder是Spring MVC框架中的一个注解,用于自定义数据绑定的方法,通过在控制器中使用@InitBinder注解,可以将特定的数据绑定逻辑应用于请求参数的处理过程中,需要的朋友可以参考下
    2023-10-10
  • 设计模式之模版方法模式_动力节点Java学院整理

    设计模式之模版方法模式_动力节点Java学院整理

    这篇文章主要介绍了设计模式之模版方法模式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Java21新特性Record Patterns示例详解

    Java21新特性Record Patterns示例详解

    这篇文章主要为大家介绍了Java21新特性Record Patterns示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • JavaWeb开发之模仿知乎首页完整代码

    JavaWeb开发之模仿知乎首页完整代码

    这篇文章主要介绍了JavaWeb开发之模仿知乎首页完整代码的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-11-11
  • Spring使用@responseBody与序列化详解

    Spring使用@responseBody与序列化详解

    这篇文章主要介绍了Spring使用@responseBody与序列化详解,@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据,需要的朋友可以参考下
    2023-08-08
  • Java入门教程--带包的类如何编译与运行

    Java入门教程--带包的类如何编译与运行

    我们一般都是通过IDE(如Eclipse、Intellij Idea,STS等)来开发,调试java项目。在不借助IDE的情况下,如何编译、运行Java程序。打包编译时,会自动创建包目录,不需要自己新建包名文件夹。
    2022-12-12
  • Java构造器使用方法及注意事项

    Java构造器使用方法及注意事项

    这篇文章主要介绍了Java构造器使用方法及注意事项的相关资料,这里举例说明如何使用构造器及需要注意的地方,需要的朋友可以参考下
    2017-07-07

最新评论