Spring中Eureka的自我保護(hù)詳解
Eureka的自我保護(hù)
當(dāng)Eureka Server節(jié)點(diǎn)在短時(shí)間內(nèi)丟失過(guò)多客戶(hù)端時(shí)(可能發(fā)生了網(wǎng)絡(luò)分區(qū)故障),那么這個(gè)節(jié)點(diǎn)就會(huì)進(jìn)入自我保護(hù)模式。一旦進(jìn)入該模式,Eureka Server就會(huì)保護(hù)服務(wù)注冊(cè)表中的信息,不再刪除服務(wù)注冊(cè)表中的數(shù)據(jù)(也就是不會(huì)注銷(xiāo)任何微服務(wù))。當(dāng)網(wǎng)絡(luò)故障恢復(fù)后,該Eureka Server節(jié)點(diǎn)會(huì)自動(dòng)退出自我保護(hù)模式。
如果想研究自我保護(hù)機(jī)制,那就要從服務(wù)下線那里,因?yàn)樽晕冶Wo(hù)來(lái)決定是讓eureka進(jìn)行剔除服務(wù)的,下線代碼如下:
public void evict(long additionalLeaseMs) {
logger.debug("Running the evict task");
//是否允許主動(dòng)摘除故障的服務(wù)實(shí)例
if (!isLeaseExpirationEnabled()) {
logger.debug("DS: lease expiration is currently disabled.");
return;
}
....
}@Override
public boolean isLeaseExpirationEnabled() {
//默認(rèn)是true,關(guān)閉自我保護(hù)機(jī)制的話,這個(gè)方法永遠(yuǎn)返回true,隨時(shí)都可以清除故障的服務(wù)實(shí)例。
if (!isSelfPreservationModeEnabled()) {
// The self preservation mode is disabled, hence allowing the instances to expire.
return true;
}
//numberOfRenewsPerMinThreshold 這個(gè)是我期望的一分鐘發(fā)送多少心跳。
//getNumOfRenewsInLastMin 這個(gè)是上一分鐘一共發(fā)來(lái)多少心跳
return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
}觸發(fā)的機(jī)制就是說(shuō),如果最近一分鐘發(fā)過(guò)來(lái)的心跳小于期望的值,這進(jìn)入心跳保護(hù)機(jī)制。那么就來(lái)看一下,這個(gè)期望的值是什么算出來(lái)的。
首先在初始化的時(shí)候,就會(huì)給他先賦值,默認(rèn)值為其他server拉著的注冊(cè)表信息的數(shù)量乘以2
// EurekaBootStrap.java
protected void initEurekaServerContext() throws Exception {
// ... 省略其它代碼
// 【2.2.10】從其他 Eureka-Server 拉取注冊(cè)信息
// 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());然后再上線,下線,故障的時(shí)候都會(huì)對(duì)他進(jìn)行修改。

由于以前的版本為硬編碼,是直接乘以2的,近期的版本,對(duì)代碼進(jìn)行了優(yōu)化,因?yàn)樾奶?0秒發(fā)來(lái)一次,所以直接用60/30,然后在乘以0.85。
為什么乘以續(xù)租百分比
低于這個(gè)百分比,意味著開(kāi)啟自我保護(hù)機(jī)制。默情況下,eureka.renewalPercentThreshold = 0.85 。
如果你真的調(diào)整了續(xù)租頻率,可以等比去續(xù)租百分比,以保證合適的觸發(fā)自我保護(hù)機(jī)制的閥值。另外,你需要注意,續(xù)租頻率是 Client 級(jí)別,續(xù)租百分比是 Server 級(jí)別。
protected void updateRenewsPerMinThreshold() {
this.numberOfRenewsPerMinThreshold = (int) (this.expectedNumberOfClientsSendingRenews
* (60.0 / serverConfig.getExpectedClientRenewalIntervalSeconds())
* serverConfig.getRenewalPercentThreshold());
}以前的代碼是有bug的,只對(duì)下線的代碼進(jìn)行了修改,故障是沒(méi)有的,近期版本也做了修復(fù)。把剔除服務(wù)的相關(guān)代碼都抽取了出來(lái)了,形成了internalCancel方法,被下面的2個(gè)方法調(diào)用,在它的方法里,做了減法。


定時(shí)更新
Eureka-Server 定時(shí)重新計(jì)算 numberOfRenewsPerMinThreshold 、expectedNumberOfRenewsPerMin 。
實(shí)現(xiàn)代碼如下:
// PeerAwareInstanceRegistryImpl.java
private void scheduleRenewalThresholdUpdateTask() {
timer.schedule(new TimerTask() {
@Override
public void run() {
updateRenewalThreshold();
}
}, serverConfig.getRenewalThresholdUpdateIntervalMs(),
serverConfig.getRenewalThresholdUpdateIntervalMs());
}
// AbstractInstanceRegistry.java
/**
* 自我保護(hù)機(jī)鎖
*
* 當(dāng)計(jì)算如下參數(shù)時(shí)使用:
* 1. {@link #numberOfRenewsPerMinThreshold}
* 2. {@link #expectedNumberOfRenewsPerMin}
*/
protected final Object lock = new Object();
private void updateRenewalThreshold() {
try {
// 計(jì)算 應(yīng)用實(shí)例數(shù)
Applications apps = eurekaClient.getApplications();
int count = 0;
for (Application app : apps.getRegisteredApplications()) {
for (InstanceInfo instance : app.getInstances()) {
if (this.isRegisterable(instance)) {
++count;
}
}
}
// 計(jì)算 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注冊(cè)表,默認(rèn)是15分鐘,會(huì)跑一次定時(shí)任務(wù),算一下服務(wù)實(shí)例的數(shù)量,如果從別的eureka server拉取到的服務(wù)實(shí)例的數(shù)量,大于當(dāng)前的服務(wù)實(shí)例的數(shù)量,會(huì)重新計(jì)算一下,主要是跟其他的eureka server做一下同步
到此這篇關(guān)于Spring中Eureka的自我保護(hù)詳解的文章就介紹到這了,更多相關(guān)Eureka的自我保護(hù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring的Eureka續(xù)約(心跳檢測(cè))詳解
- Spring中的Eureka服務(wù)過(guò)期詳細(xì)解析
- SpringCloud啟動(dòng)eureka server后,沒(méi)報(bào)錯(cuò)卻不能訪問(wèn)管理頁(yè)面(404問(wèn)題)
- SpringCloud集成Eureka并實(shí)現(xiàn)負(fù)載均衡的過(guò)程詳解
- SpringCloud中的Eureka注冊(cè)中心詳細(xì)解讀
- springboot?去掉netflix?禁用Eureka的解決方法
- SpringCloud中的Eureka集群配置方法
- Spring Cloud Nacos 和 Eureka區(qū)別解析
相關(guān)文章
java 異常之手動(dòng)拋出與自動(dòng)拋出的實(shí)例講解
這篇文章主要介紹了java 異常之手動(dòng)拋出與自動(dòng)拋出的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
SpringBoot集成easy-rules規(guī)則引擎流程詳解
這篇文章主要介紹了SpringBoot集成easy-rules規(guī)則引擎流程,合理的使用規(guī)則引擎可以極大的減少代碼復(fù)雜度,提升代碼可維護(hù)性。業(yè)界知名的開(kāi)源規(guī)則引擎有Drools,功能豐富,但也比較龐大2023-03-03
解析Mybatis Porxy動(dòng)態(tài)代理和sql解析替換問(wèn)題
這篇文章主要介紹了Mybatis Porxy動(dòng)態(tài)代理和sql解析替換,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04

