eureka.instance.leaseRenewalIntervalInSeconds = 30 # hearbeat interval eureka.server.renewalPercentThreshold = 0.85 eureka.server.renewalThresholdUpdateIntervalMs = 15 * 60 * 1000 # 15mins
client發送心跳的頻率html
觸發自我保護的心跳數比例閾值java
多久重置一下心跳閾值node
factor = 60/leaseRenewalIntervalInSecondsweb
factor * Nspring
factor N renewalPercentThreshold微信
this.expectedNumberOfRenewsPerMin = N * 2; this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
eureka-core-1.4.12-sources.jar!/com/netflix/eureka/registry/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()); 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 =1app
eureka-core-1.4.12-sources.jar!/com/netflix/eureka/registry/AbstractInstanceRegistry.javaide
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) { try { read.lock(); Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName()); REGISTER.increment(isReplication); if (gMap == null) { final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>(); gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap); if (gMap == null) { gMap = gNewMap; } } Lease<InstanceInfo> existingLease = gMap.get(registrant.getId()); // Retain the last dirty timestamp without overwriting it, if there is already a lease if (existingLease != null && (existingLease.getHolder() != null)) { Long existingLastDirtyTimestamp = existingLease.getHolder().getLastDirtyTimestamp(); Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp(); logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp); if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp) { logger.warn("There is an existing lease and the existing lease's dirty timestamp {} is greater" + " than the one that is being registered {}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp); logger.warn("Using the existing instanceInfo instead of the new instanceInfo as the registrant"); registrant = existingLease.getHolder(); } } else { // The lease does not exist and hence it is a new registration 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()); } } logger.debug("No previous lease information found; it is new registration"); } Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration); if (existingLease != null) { lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp()); } gMap.put(registrant.getId(), lease); synchronized (recentRegisteredQueue) { recentRegisteredQueue.add(new Pair<Long, String>( System.currentTimeMillis(), registrant.getAppName() + "(" + registrant.getId() + ")")); } // This is where the initial state transfer of overridden status happens if (!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) { logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the " + "overrides", registrant.getOverriddenStatus(), registrant.getId()); if (!overriddenInstanceStatusMap.containsKey(registrant.getId())) { logger.info("Not found overridden id {} and hence adding it", registrant.getId()); overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus()); } } InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(registrant.getId()); if (overriddenStatusFromMap != null) { logger.info("Storing overridden status {} from map", overriddenStatusFromMap); registrant.setOverriddenStatus(overriddenStatusFromMap); } // Set the status based on the overridden status rules InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication); registrant.setStatusWithoutDirty(overriddenInstanceStatus); // If the lease is registered with UP status, set lease service up timestamp if (InstanceStatus.UP.equals(registrant.getStatus())) { lease.serviceUp(); } registrant.setActionType(ActionType.ADDED); recentlyChangedQueue.add(new RecentlyChangedItem(lease)); registrant.setLastUpdatedTimestamp(); invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress()); logger.info("Registered instance {}/{} with status {} (replication={})", registrant.getAppName(), registrant.getId(), registrant.getStatus(), isReplication); } finally { read.unlock(); } }
其中,重點看這段post
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());
leaseRenewalIntervalInSeconds: 10 --> 每分鐘6次 this.expectedNumberOfRenewsPerMin = N * 2 = 32 ; this.numberOfRenewsPerMinThreshold = (int) (32 * 0.85) = (int)27.2 = 27;
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多算了一個實例的心跳次數,因此以下:
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;
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
想獲取最新內容,請關注微信公衆號