­

Eureka詳解系列(五)–Eureka Server部分的源碼和配置

簡介

按照原定的計劃,我將分三個部分來分析 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 的源碼和配置,具體的細節歡迎私信交流。

最後,感謝您的閱讀。

參考資料

//github.com/Netflix/eureka/wiki/Eureka-at-a-glance

相關源碼請移步://github.com/ZhangZiSheng001/eureka-demo

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