Eureka詳解系列(五)--Eureka Server部分的原始碼和配置

子月生發表於2021-02-10

簡介

按照原定的計劃,我將分三個部分來分析 Eureka 的原始碼:

  1. Eureka 的配置體系(已經寫完,見Eureka詳解系列(三)--探索Eureka強大的配置體系);
  2. Eureka Client 的互動行為(已經寫完,見Eureka詳解系列(四)--Eureka Client部分的原始碼和配置 );
  3. 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 的整個互動過程。

zzs_eureka_21

首先,Eureka Server 需要和 Eureka Client 互動,所以它需要能夠處理 Eureka Client 的各種請求,這些請求包括:

  1. 獲取登錄檔(Application Client 的請求);
  2. 註冊、續約、登出例項(Application Service 的請求);

除此之外,在叢集中,它需要和對等節點互動,互動內容主要包括:

  1. 將自己的登錄檔變更操作同步到其他節點
  2. 處理其他節點同步登錄檔的請求

其實,一個完整的 Eureka Server 專案本身也包含了 Eureka Client 的部分,也就是說,它可以註冊自己和消費包括自己在內的服務,可以在 eureka-client.properties 增加以下配置來關閉掉這兩個部分的功能(不建議這麼做):

# 當前例項是否註冊到Eureka Server。預設true
eureka.registration.enabled=false
# 當前例項是否需要從Eureka Server獲取服務登錄檔
eureka.shouldFetchRegistry=false

如何實現這些功能

知道了 Eureka Server 需要具備哪些功能,接下來我們就從原始碼的角度來看看怎樣實現這些功能。

和之前一樣,我更多的會從設計的層面來分析,而不會順序地去看每個過程的程式碼,即重設計、輕實現。

那麼,還是從一個 UML 圖開始吧。有了它,相信大家看原始碼時會更輕鬆一些。

zzs_eureka_20

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還啟動了三個定時任務:

  1. 更新PeerEurekaNode列表。例如,當我們使用 DNS 配合 serviceUrl 時,對等節點的地址可能會變化,所以需要及時更新。這個定時任務用於支援叢集的故障轉移和擴容。
  2. 更新引數 numberOfRenewsPerMinThreshold--每分鐘至少要有多少例項續約。當每分鐘續約例項少於這個值時(eureka 認為是災難性的網路故障導致的),Eureka Server 將進入自我保護模式,此時,它不會再主動淘汰例項,直到我們主動關閉該模式,或者續約例項達到了閾值。我們一般可以通過以下引數來控制。而每分鐘至少要有多少例項續約,這個數值受到例項總數的影響,所以需要定時更新。
# 期望例項多久續約一次
eureka.expectedClientRenewalIntervalSeconds=30
# 續約例項的閾值,未達到將開啟自我保護模式
eureka.renewalPercentThreshold=0.85
# 是否啟用保護模式
eureka.enableSelfPreservation=true
  1. 丟棄未能及時續約的例項。預設情況下,例項超過 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 裡,配置分成了三種:

  1. EurekaInstanceConfig:當前例項身份的配置資訊,即我是誰?
  2. EurekaServerConfig:一些影響當前Eureka Server和客戶端或對等節點互動行為的配置資訊,即怎麼互動?
  3. 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://github.com/ZhangZiSheng001/eureka-demo

本文為原創文章,轉載請附上原文出處連結:https://www.cnblogs.com/ZhangZiSheng001/p/14395079.html

相關文章