Spring中Eureka的自我保護詳解
Eureka的自我保護
當(dāng)Eureka Server節(jié)點在短時間內(nèi)丟失過多客戶端時(可能發(fā)生了網(wǎng)絡(luò)分區(qū)故障),那么這個節(jié)點就會進入自我保護模式。一旦進入該模式,Eureka Server就會保護服務(wù)注冊表中的信息,不再刪除服務(wù)注冊表中的數(shù)據(jù)(也就是不會注銷任何微服務(wù))。當(dāng)網(wǎng)絡(luò)故障恢復(fù)后,該Eureka Server節(jié)點會自動退出自我保護模式。
如果想研究自我保護機制,那就要從服務(wù)下線那里,因為自我保護來決定是讓eureka進行剔除服務(wù)的,下線代碼如下:
public void evict(long additionalLeaseMs) { logger.debug("Running the evict task"); //是否允許主動摘除故障的服務(wù)實例 if (!isLeaseExpirationEnabled()) { logger.debug("DS: lease expiration is currently disabled."); return; } .... }
@Override public boolean isLeaseExpirationEnabled() { //默認是true,關(guān)閉自我保護機制的話,這個方法永遠返回true,隨時都可以清除故障的服務(wù)實例。 if (!isSelfPreservationModeEnabled()) { // The self preservation mode is disabled, hence allowing the instances to expire. return true; } //numberOfRenewsPerMinThreshold 這個是我期望的一分鐘發(fā)送多少心跳。 //getNumOfRenewsInLastMin 這個是上一分鐘一共發(fā)來多少心跳 return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold; }
觸發(fā)的機制就是說,如果最近一分鐘發(fā)過來的心跳小于期望的值,這進入心跳保護機制。那么就來看一下,這個期望的值是什么算出來的。
首先在初始化的時候,就會給他先賦值,默認值為其他server拉著的注冊表信息的數(shù)量乘以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());
然后再上線,下線,故障的時候都會對他進行修改。
由于以前的版本為硬編碼,是直接乘以2的,近期的版本,對代碼進行了優(yōu)化,因為心跳是30秒發(fā)來一次,所以直接用60/30,然后在乘以0.85。
為什么乘以續(xù)租百分比
低于這個百分比,意味著開啟自我保護機制。默情況下,eureka.renewalPercentThreshold = 0.85 。
如果你真的調(diào)整了續(xù)租頻率,可以等比去續(xù)租百分比,以保證合適的觸發(fā)自我保護機制的閥值。另外,你需要注意,續(xù)租頻率是 Client 級別,續(xù)租百分比是 Server 級別。
protected void updateRenewsPerMinThreshold() { this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews * (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds()) * serverConfig.getRenewalPercentThreshold()); }
以前的代碼是有bug的,只對下線的代碼進行了修改,故障是沒有的,近期版本也做了修復(fù)。把剔除服務(wù)的相關(guān)代碼都抽取了出來了,形成了internalCancel方法,被下面的2個方法調(diào)用,在它的方法里,做了減法。
定時更新
Eureka-Server 定時重新計算 numberOfRenewsPerMinThreshold 、expectedNumberOfRenewsPerMin 。
實現(xiàn)代碼如下:
// PeerAwareInstanceRegistryImpl.java private void scheduleRenewalThresholdUpdateTask() { timer.schedule(new TimerTask() { @Override public void run() { updateRenewalThreshold(); } }, serverConfig.getRenewalThresholdUpdateIntervalMs(), serverConfig.getRenewalThresholdUpdateIntervalMs()); } // AbstractInstanceRegistry.java /** * 自我保護機鎖 * * 當(dāng)計算如下參數(shù)時使用: * 1. {@link #numberOfRenewsPerMinThreshold} * 2. {@link #expectedNumberOfRenewsPerMin} */ protected final Object lock = new Object(); private void updateRenewalThreshold() { try { // 計算 應(yīng)用實例數(shù) Applications apps = eurekaClient.getApplications(); int count = 0; for (Application app : apps.getRegisteredApplications()) { for (InstanceInfo instance : app.getInstances()) { if (this.isRegisterable(instance)) { ++count; } } } // 計算 expectedNumberOfRenewsPerMin 、 numberOfRenewsPerMinThreshold 參數(shù) 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分鐘,會跑一次定時任務(wù),算一下服務(wù)實例的數(shù)量,如果從別的eureka server拉取到的服務(wù)實例的數(shù)量,大于當(dāng)前的服務(wù)實例的數(shù)量,會重新計算一下,主要是跟其他的eureka server做一下同步
到此這篇關(guān)于Spring中Eureka的自我保護詳解的文章就介紹到這了,更多相關(guān)Eureka的自我保護內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot集成easy-rules規(guī)則引擎流程詳解
這篇文章主要介紹了SpringBoot集成easy-rules規(guī)則引擎流程,合理的使用規(guī)則引擎可以極大的減少代碼復(fù)雜度,提升代碼可維護性。業(yè)界知名的開源規(guī)則引擎有Drools,功能豐富,但也比較龐大2023-03-03解析Mybatis Porxy動態(tài)代理和sql解析替換問題
這篇文章主要介紹了Mybatis Porxy動態(tài)代理和sql解析替換,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04