簡介
按照原定的計划,我將分三個部分來分析 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
