續租、下線等操做比較直觀,實際上也不復雜。讓咱們本身想一想它們大概會在服務端有什麼操做。java
lastUpdateTimestamp
, 更新一下InstanceInfo的最新狀態。而後調用其餘同伴節點的renew接口。evictionTimestamp
,而後設置InstanceInfo爲已刪除。而後把lease加入到recentlyChangedQueue
中。最後調用同伴節點的cancel接口。—— 服務端確實作了差很少這些事情。所以爲了避免影響其餘重要事件,這裏再也不繼續深刻。數組
Eureka選擇作一個支持AP的系統(CAP定理)。其實很好理解,當發生大量應用實例再也不renew時,服務端認爲發生了網絡分區。Eureka爲了保證高可用,再也不踢掉已經到期的lease,從而讓依賴於該服務端實例的client端仍然能正常進行服務發現(儘管存在服務實例確實掛掉的可能,即犧牲了一致性)。bash
在Spring Cloud Eureka的Home頁面上面常常會見到這個警告,就是啓用了自我保護機制。網絡
關於這個問題網上的解釋也不少了,下面這篇文章提供了幾幅有用的圖:ide
The Mystery of Eureka Self-Preservation編碼
這篇文章有全部你想要的。 Eureka 源碼解析 —— 應用實例註冊發現(四)之自我保護機制spa
搬過來一些重點:code
看代碼cdn
// PeerAwareInstanceRegistryImpl.java
@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;
}
複製代碼
當每分鐘心跳次數(
renewsLastMin
) 小於numberOfRenewsPerMinThreshold
時,而且開啓自動保護模式開關(eureka.server.enableSelfPreservation = true
) 時,觸發自動保護機制,再也不自動過時租約。server
其中:
numberOfRenewsPerMinThreshold
= expectedNumberOfRenewsPerMin
* 續租百分比( eureka.server.renewalPercentThreshold
, 默認0.85 )expectedNumberOfRenewsPerMin
= 當前註冊的應用實例數 x 2爲何乘以 2:
默認狀況下,註冊的應用實例每半分鐘續租一次,那麼一分鐘心跳兩次,所以 x 2 。
這裏有硬編碼的狀況,所以修改應用實例的續租頻率會讓計算不太準。不過,自我保護機制我比較懷疑它的重要性,該調還得調。
有四個地方會從新計算numberOfRenewsPerMinThreshold
、 expectedNumberOfRenewsPerMin
。
eureka.server.renewalThresholdUpdateIntervalMs
控制。清理過時lease的也是一個定時任務EvictionTask
,頻率由eureka.server.evictionIntervalTimerInMs
,默認爲60秒。
EvictionTask
代碼class EvictionTask extends TimerTask {
@Override
public void run() {
try {
// 獲取 補償時間毫秒數
long compensationTimeMs = getCompensationTimeMs();
logger.info("Running the evict task with compensationTime {}ms", compensationTimeMs);
// 清理過時租約邏輯
evict(compensationTimeMs);
} catch (Throwable e) {
logger.error("Could not run the evict task", e);
}
}
}
複製代碼
那個getCompensationTimeMs()
方法的意思是,定時器可能比設定的時間更晚觸發,緣由多是GC等。假設原本要在上一次執行後60s再次觸發,但由於GC在第70秒才被觸發,這時去檢查有沒有lease有沒有超期無renew不能用70s來算,而應該還用60s來算,由於在這10s的GC時間中,極可能此服務端沒法處理註冊請求。補償的10s就是這個意思,就是容許實例多超期這10s。
evict(compensationTime)
又比較長,下面分段分析。
lastUpdatedTime
+ duration
+ compensationTime
,若是前者大,說明已過時。eureka.server.renewalPercentThreshold
,默認又是0.85。這個閾值仍是很高的,若是有大量實例過時,就須要分多批執行才能清理完。internalCancel
處理每一個要被清理的lease,這個方法就是前面的cancel階段會調的。這個自動清理彷佛沒有告知同伴節點,你們各作各的。可見Eureka的一致性是蠻低的。