簡介
按照原定的計劃,我將分三個部分來分析 Eureka 的原始碼:
- Eureka 的配置體系(已經寫完,見Eureka詳解系列(三)--探索Eureka強大的配置體系);
- Eureka Client 的互動行為(已經寫完,見Eureka詳解系列(四)--Eureka Client部分的原始碼和配置 );
- Eureka Server 的互動行為。
今天,我們來研究第三部分的原始碼。
分析的思路和第二部分的一樣,先明確 Eureka Server 需要具備哪些功能,再從原始碼層面分析如何實現這些功能,最後補充 Eureka Server 的配置解讀。
專案環境
os:win 10
jdk:1.8.0_231
eureka:1.10.11
tomcat:9.0.21
Eureka Server 的功能
還是來回顧 Eureka 的整個互動過程。
首先,Eureka Server 需要和 Eureka Client 互動,所以它需要能夠處理 Eureka Client 的各種請求,這些請求包括:
- 獲取登錄檔(Application Client 的請求);
- 註冊、續約、登出例項(Application Service 的請求);
除此之外,在叢集中,它需要和對等節點互動,互動內容主要包括:
- 將自己的登錄檔變更操作同步到其他節點;
- 處理其他節點同步登錄檔的請求。
其實,一個完整的 Eureka Server 專案本身也包含了 Eureka Client 的部分,也就是說,它可以註冊自己和消費包括自己在內的服務,可以在 eureka-client.properties 增加以下配置來關閉掉這兩個部分的功能(不建議這麼做):
# 當前例項是否註冊到Eureka Server。預設true
eureka.registration.enabled=false
# 當前例項是否需要從Eureka Server獲取服務登錄檔
eureka.shouldFetchRegistry=false
如何實現這些功能
知道了 Eureka Server 需要具備哪些功能,接下來我們就從原始碼的角度來看看怎樣實現這些功能。
和之前一樣,我更多的會從設計的層面來分析,而不會順序地去看每個過程的程式碼,即重設計、輕實現。
那麼,還是從一個 UML 圖開始吧。有了它,相信大家看原始碼時會更輕鬆一些。
AbstractInstanceRegistry
裡放了一張登錄檔,用來存放所有的例項物件,通過它可以處理 Eureka Client 或者其他 Eureka Server 的請求,包括註冊、續約、登出例項以及獲取登錄檔等。
它的子類PeerAwareInstanceRegistryImpl
提供了多節點的支援,這裡以續約例項的方法為例,相同的操作還會被同步到其他節點(對等節點的請求除外)。
public boolean renew(final String appName, final String id, final boolean isReplication) {
// 先呼叫父類AbstractInstanceRegistry的方法
if (super.renew(appName, id, isReplication)) {
// 再將操作同步到其他節點,最終是呼叫PeerEurekaNode的方法進行同步
replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication);
return true;
}
return false;
}
除此之外,PeerAwareInstanceRegistryImpl
還啟動了三個定時任務:
- 更新
PeerEurekaNode
列表。例如,當我們使用 DNS 配合 serviceUrl 時,對等節點的地址可能會變化,所以需要及時更新。這個定時任務用於支援叢集的故障轉移和擴容。 - 更新引數 numberOfRenewsPerMinThreshold--每分鐘至少要有多少例項續約。當每分鐘續約例項少於這個值時(eureka 認為是災難性的網路故障導致的),Eureka Server 將進入自我保護模式,此時,它不會再主動淘汰例項,直到我們主動關閉該模式,或者續約例項達到了閾值。我們一般可以通過以下引數來控制。而每分鐘至少要有多少例項續約,這個數值受到例項總數的影響,所以需要定時更新。
# 期望例項多久續約一次
eureka.expectedClientRenewalIntervalSeconds=30
# 續約例項的閾值,未達到將開啟自我保護模式
eureka.renewalPercentThreshold=0.85
# 是否啟用保護模式
eureka.enableSelfPreservation=true
- 丟棄未能及時續約的例項。預設情況下,例項超過 90s 未能續約的話,Eureka Server 會將其丟棄掉。
從哪裡開始看原始碼
Eureka Server 是作為一個 Web 應用執行的,要看原始碼比較難找到入口。開啟Eureka詳解系列(二)--如何使用Eureka(原生API,無Spring) 例子裡的 web.xml,可以看到配置了一個監聽器,這個類就是 Eureka Server 初始化的入口。
<listener>
<listener-class>com.netflix.eureka.EurekaBootStrap</listener-class>
</listener>
在這個類裡面,我們主要關注這一段程式碼(程式碼有刪減)。
protected void initEurekaServerContext() throws Exception {
// 下面這一段是為了初始化Eureka Client所需要的物件,上一篇部落格講過了
EurekaInstanceConfig instanceConfig = new MyDataCenterInstanceConfig();
ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(
instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
// 載入eureka-server.properties的配置
EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);
// 初始化登錄檔物件(支援多節點)
PeerAwareInstanceRegistry registry = new PeerAwareInstanceRegistryImpl(
eurekaServerConfig,
eurekaClient.getEurekaClientConfig(),
serverCodecs,
eurekaClient
);
// 初始化PeerEurekaNodes物件
PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(
registry,
eurekaServerConfig,
eurekaClient.getEurekaClientConfig(),
serverCodecs,
applicationInfoManager
);
// 1. 初始化PeerEurekaNode列表,
// 2. 啟動定時任務:更新PeerEurekaNode列表
peerEurekaNodes.start();
// 1. 將PeerEurekaNode列表的指標給到PeerEurekaNodes物件物件
// 2. 啟動定時任務:更新引數numberOfRenewsPerMinThreshold--每分鐘至少要有多少例項續約,它是判斷是否開啟自我保護模式的依據
registry.init(peerEurekaNodes);
// 從其他節點獲取例項列表並註冊到本地的登錄檔
int registryCount = registry.syncUp();
// 1. 初始化引數numberOfRenewsPerMinThreshold--每分鐘要求多少例項續約
// 2. 開啟定時任務:淘汰未能正常續約的例項
registry.openForTraffic(applicationInfoManager, registryCount);
}
完成初始化後,Eureka Server 就可以處理 Eureka Client 的請求了。因為 Eureka Server 使用 jersey 作 Web 框架(jersey 和 struts2、springMVC 作用差不多,沒接觸過也不礙事),所以,只要找到新增了javax.ws.rs.Path
註解的類,就能找到這部分程式碼的入口。
Eureka Server 的配置解讀
回顧下Eureka詳解系列(三)--探索Eureka強大的配置體系的內容,在 Eureka 裡,配置分成了三種:
- EurekaInstanceConfig:當前例項身份的配置資訊,即我是誰?
- EurekaServerConfig:一些影響當前Eureka Server和客戶端或對等節點互動行為的配置資訊,即怎麼互動?
- EurekaClientConfig:一些影響當前例項和Eureka Server互動行為的配置資訊,即和誰互動?怎麼互動?
這裡我們來講講EurekaServerConfig
的配置引數,對應的是 eureka-server.properties 裡的配置。
# 期望例項多久續約一次
eureka.expectedClientRenewalIntervalSeconds=30
# 續約例項的閾值,未達到將開啟自我保護模式
eureka.renewalPercentThreshold=0.85
# 是否啟用保護模式
eureka.enableSelfPreservation=true
# 更新引數numberOfRenewsPerMinThreshold的定時任務多久執行一次
renewalThresholdUpdateIntervalM=900000
# 更新PeerEurekaNode列表的定時任務多久執行一次
peerEurekaNodesUpdateIntervalMs=600000
# 淘汰未能正常續約例項的定時任務多久執行一次
evictionIntervalTimerInMs=60000
# 這幾個一般不用,我就不展開了。有需要的話可以
#awsAccessId=
#awsSecretKey=
eipBindRebindRetries=3
eipBindRebindRetryIntervalMsWhenUnbound=60000
eipBindRebindRetryIntervalMs=300000
waitTimeInMsWhenSyncEmpty=300000
shouldBatchReplication=false
disableDelta=false
numberRegistrySyncRetries=5
registrySyncRetryWaitMs=30000
enableReplicatedRequestCompression=false
minAvailableInstancesForPeerReplication=-1
peerEurekaStatusRefreshTimeIntervalMs=30000
peerNodeConnectTimeoutMs=1000
peerNodeReadTimeoutMs=5000
peerNodeTotalConnections=1000
peerNodeTotalConnectionsPerHost=500
numberOfReplicationRetries=5
maxElementsInPeerReplicationPool=10000
maxIdleThreadAgeInMinutesForPeerReplication=15
minThreadsForPeerReplication=5
maxThreadsForPeerReplication=20
maxTimeForReplication=30000
primeAwsReplicaConnections=true
maxIdleThreadAgeInMinutesForStatusReplication=10
minThreadsForStatusReplication=1
maxThreadsForStatusReplication=1
maxElementsInStatusReplicationPool=10000
disableDeltaForRemoteRegions=false
remoteRegionConnectTimeoutMs=2000
remoteRegionReadTimeoutMs=5000
remoteRegionTotalConnections=1000
remoteRegionTotalConnectionsPerHost=500
remoteRegionConnectionIdleTimeoutSeconds=30
remoteRegion.gzipContent=true
#remoteRegionUrlsWithName=
#remoteRegion.appWhiteList=
remoteRegion.registryFetchIntervalInSeconds=30
remoteRegion.fetchThreadPoolSize=20
#remoteRegion.trustStoreFileName=
remoteRegion.trustStorePassword=changeit
remoteRegion.disable.transparent.fallback=false
shouldUseAwsAsgApi=true
asgQueryTimeoutMs=300
asgUpdateIntervalMs=300000
asgCacheExpiryTimeoutMs=600000
retentionTimeInMSInDeltaQueue=180000
deltaRetentionTimerIntervalInMs=30000
responseCacheAutoExpirationInSeconds=180
responseCacheUpdateIntervalMs=30000
shouldUseReadOnlyResponseCache=true
syncWhenTimestampDiffers=true
auth.shouldLogIdentityHeaders=true
route53BindRebindRetries=3
route53BindRebindRetryIntervalMs=300000
route53DomainTTL=30
initialCapacityOfResponseCache=1000
jsonCodecName=com.netflix.discovery.converters.wrappers.CodecWrappers.LegacyJacksonJson
xmlCodecName=com.netflix.discovery.converters.wrappers.CodecWrappers.XStreamXml
以上比較巨集觀地講完了 Eureka Server 的原始碼和配置,具體的細節歡迎私信交流。
最後,感謝您的閱讀。
參考資料
https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance
本文為原創文章,轉載請附上原文出處連結:https://www.cnblogs.com/ZhangZiSheng001/p/14395079.html