相关参数
eureka.instance.leaseRenewalIntervalInSeconds = 30 # hearbeat interval
eureka.server.renewalPercentThreshold = 0.85
eureka.server.renewalThresholdUpdateIntervalMs = 15 * 60 * 1000 # 15mins
leaseRenewalIntervalInSeconds
client发送心跳的频率
renewalPercentThreshold
触发自我保护的心跳数比例阈值
renewalThresholdUpdateIntervalMs
多久重置一下心跳阈值
计算公式
Number of heartbeats expected from one client instance / min
factor = 60/leaseRenewalIntervalInSeconds
Number of heartbeats expected from N instances / min
factor * N
Minimum expected heartbeat threshold / min
factor N renewalPercentThreshold
源代码
this.expectedNumberOfRenewsPerMin = N * 2;
this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
eureka启动时
eureka-core-1.4.12-sources.jar!/com/netflix/eureka/registry/PeerAwareInstanceRegistryImpl.java
@Overridepublic 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());logger.info("Got " + count + " instances from neighboring DS node");logger.info("Renew threshold is: " + numberOfRenewsPerMinThreshold);this.startupTime = System.currentTimeMillis();if (count > 0) {this.peerInstancesTransferEmptyOnStartup = false;}DataCenterInfo.Name selfName = applicationInfoManager.getInfo().getDataCenterInfo().getName();boolean isAws = Name.Amazon == selfName;if (isAws && serverConfig.shouldPrimeAwsReplicaConnections()) {logger.info("Priming AWS connections for all replicas..");primeAwsReplicas(applicationInfoManager);}logger.info("Changing status to UP");applicationInfoManager.setInstanceStatus(InstanceStatus.UP);super.postInit();}
count为eureka个数,此时expectedNumberOfRenewsPerMin为2(1个注册中心,每30秒发送一次心跳,则每分钟对于每个client,应该发送2次心跳),numberOfRenewsPerMinThreshold=(int)2*0.85 =1
client注册时
eureka-core-1.4.12-sources.jar!/com/netflix/eureka/registry/AbstractInstanceRegistry.java
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {try {read.lock();Map
其中,重点看这段
synchronized (lock) {if (this.expectedNumberOfRenewsPerMin > 0) {// Since the client wants to cancel it, reduce the threshold// (1// for 30 seconds, 2 for a minute)this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin + 2;this.numberOfRenewsPerMinThreshold =(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());}}
每注册上一个实例,重新算一下,即
this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin + 2;
this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
总的来说,所有实例都注册上了,就是
this.expectedNumberOfRenewsPerMin = N * 2;
this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
计算例子
2个eureka,算在内,factor=6,N:16
leaseRenewalIntervalInSeconds: 10 --> 每分钟6次
this.expectedNumberOfRenewsPerMin = N * 2 = 32 ;
this.numberOfRenewsPerMinThreshold = (int) (32 * 0.85) = (int)27.2 = 27;
2个eureka,算在内,factor=2,N=3
leaseRenewalIntervalInSeconds: 30 --> 每分钟2次
this.expectedNumberOfRenewsPerMin = N * 2 = 6 ;
this.numberOfRenewsPerMinThreshold = (int) (6* 0.85) = (int)5.1 = 5;
对于单机版eureka的,比较特殊,由于openForTraffic这个方法里头
this.expectedNumberOfRenewsPerMin = count * 2;
这里count=1多算了一个实例的心跳次数,所以如下:
1个eureka,不注册,factor=2,N=1
leaseRenewalIntervalInSeconds: 30 --> 每分钟2次
this.expectedNumberOfRenewsPerMin = N * 2 = 2 ;
this.numberOfRenewsPerMinThreshold = (int) (2 * 0.85) = (int)1.7 = 1;实际显示是3,应该是按N=2算
this.expectedNumberOfRenewsPerMin = N * 2 = 4 ;
this.numberOfRenewsPerMinThreshold = (int) (4 * 0.85) = (int)3.4 = 3;
1个eureka,不注册,factor=2,N=2
leaseRenewalIntervalInSeconds: 30 --> 每分钟2次
this.expectedNumberOfRenewsPerMin = N * 2 = 4 ;
this.numberOfRenewsPerMinThreshold = (int) (4 * 0.85) = (int)3.4 = 3;
实际显示是5,应该是按N=3算
this.expectedNumberOfRenewsPerMin = N * 2 = 6 ;
this.numberOfRenewsPerMinThreshold = (int) (6 * 0.85) = (int)5.1 = 5;
反思源码
由于eureka-core-1.4.12版本里头,你去调整eureka.instance.leaseRenewalIntervalInSeconds的话,代码里头没有相应调整factor,也就是代码还是60/30=2,所以会破坏eureka内置的设计思路。不过对于小型项目来说,没有跨机房,网络没有那么恶劣的话,想避免自我保护导致的服务注册列表不能修改的问题,可以选择以下任一方式尝试下:
关闭自我保护eureka.server.enableSelfPreservation=false
调小eureka.instance.leaseRenewalIntervalInSeconds,比如设置为10秒
调小renewalPercentThreshold,比如改为0.49
另外,还有一个参数可以调整,就是心跳阈值重新计算的周期:
eureka.server.renewalThresholdUpdateIntervalMs = 15 60 1000 # 15mins
默认是15分钟可以改小一点,比如5分钟=5601000
doc
了解Spring Cloud Eureka Server自我保护和更新阈值
the-mystery-of-eurekas-self-preservation
spring cloud eureka
Understanding Spring Cloud Eureka Server self preservation and renew threshold
Eureka's self-preservation mode never recovers
想获取最新内容,请关注微信公众号