- 每一個Eureka client應用被稱作一個instance。
Eureka client應用和Eureka client也有着細微的差別,前者指的是我們自己的應用程序,后者代表的是框架提供的一個組件。(自己的應用程序需要依賴Eureka client相關的jar)
Eureka 具有很靈活的動態配置特性。既有用來設置初始配置的屬性,也有用來周期性的檢查這些配置是否有變化的配置。其中的大多數配置都可以在運行時修改,並在下一個刷新周期中起作用。例如:Eureka client用來注冊到Eureka server的URL可以動態改變,並在5分鍾后被識別(eureka.client.eurekaServiceUrlPollIntervalSeconds配置)。
- Eureka Instance (Eureka client 應用)和Eureka client主要配置
1.在Eureka中,一個instance通過一個eureka.instance.instanceId 來唯一標識,如果這個值沒有設置,就采用eureka.instance.metadataMap.instanceId來代替。
instance之間通過eureka.instance.appName 來彼此訪問,在spring cloud中默認值是spring.application.name,如果沒有設置則為UNKNOWN。
在實際使用中spring.application.name不可或缺,因為相同名字的應用會被Eureka合並成一個群集。
eureka.instance.instanceId也可以不設置,直接使用缺省值(client.hostname:application.name:port)
,同一個appName下InstanceId不能相同。
屬性eureka.instance.virtualHostName目前在spring cloud中目前沒有用,默認值是appName或者UNKNOWN。
2.如果 eureka.client.registerWithEureka設置成true(默認值true),應用啟動時,會利用指定的eureka.client.serviceUrl.defaultZone注冊到對應的Eureka server中。
之后每隔30s(通過eureka.instance.leaseRenewalIntervalInSeconds來配置)向Eureka server發送一次心跳,
如果Eureka server在90s(通過eureka.instance.leaseExpirationDurationInSeconds配置)內沒有收到某個instance發來的心跳就會把這個instance從注冊中心中移走。
發送心跳的操作是一個異步任務,如果發送失敗,則以2的指數形式延長重試的時間,直到達到eureka.instance.leaseRenewalIntervalInSeconds * eureka.client.heartbeatExecutorExponentialBackOffBound這個上限,之后一直以這個上限值作為重試間隔,直至重新連接到Eureka server,並且重新嘗試連接到Eureka server的次數是不受限制的。
3.在Eureka server中每一個instance都由一個包含大量這個instance信息的com.netflix.appinfo.InstanceInfo標識,
client向Eureka server發送心跳和更新注冊信息是不相同的,InstanceInfo也以固定的頻率發送到Eureka server,這些信息在Eureka client啟動后的40s(通過eureka.client.initialInstanceInfoReplicationIntervalSeconds配置)首次發送,之后每隔30s(通過eureka.client.instanceInfoReplicationIntervalSeconds配置)發送一次。
4.如果eureka.client.fetchRegistry設置成true(默認值true),Eureka client在啟動時會從Eureka server獲取注冊信息並緩存到本地,之后只會增量獲取信息(可以把eureka.client.shouldDisableDelta設置成false來強制每次都全量獲取)。獲取注冊信息的操作也是一個異步任務,每隔30秒執行一次(通過eureka.client.registryFetchIntervalSeconds配置),如果操作失敗,也是以2的指數形式延長重試時間,直到達到eureka.client.registryFetchIntervalSeconds * eureka.client.cacheRefreshExecutorExponentialBackOffBound 這個上限,之后一直以這個上限值作為重試間隔,直至重新獲取到注冊信息,並且重新嘗試獲取注冊信息的次數是不受限制的。
- 為什么利用Eureka注冊一個instance需要很長的時間
1.Eureka client注冊
首次心跳在Eureka client啟動后的30s,所以在這個期間中,instance不會出現在Eureka注冊中心中。
2.Eureka server響應緩存
Eureka server響應緩存每隔30s更新一次
(即其他Eureka client從Eureka serve 請求的注冊信息每隔30s才會更新,通過eureka.server.responseCacheUpdateIntervalMs配置),
所以即便instance注冊過了,也不會立即出現在調用 /eureka/apps的返回結果中
(因為Eureka面板http://eurekaserver:8761對應的頁面繞過了響應緩存,所以剛注冊過的instance會出現在Eureka面板中),
另一個API/eureka/apps/<appName>/<instanceId>也繞過了響應緩存,所以如果你知道instanceId,你也可以通過此URI來獲取instance的具體信息。
所以,為了使Eureka client能發現新注冊instance,還需要等額外的30s
3.Eureka client緩存
Eureka client本地也緩存着從Eureka server獲取的注冊信息。這個緩存也是每隔30s刷新一次(通過eureka.client.registryFetchIntervalSeconds配置),
所以這個地方又有可能需要30s來使Eureka client刷新本地緩存並把新注冊的instance獲取下來
4.負載均衡器緩存
Ribbon是從本地的Eureka client中獲取信息來執行負載均衡,ribbon自己也維護了一個緩存來避免每次請求都要調用Eureka client。ribbon緩存默認也是30s刷新一次(通過ribbon.ServerListRefreshInterval配置),所以在ribbon能利用新注冊的instance之前可能還需要30s。
綜上所述,一個新注冊的instance在和別的instance通信之前可能需要2min的間隔。
- Eureka server的peer-aware模式
1.Eureka server還有一種peer-aware模式,可以和其他的Eureka server相互復制注冊信息,從而對外提供負載均衡和彈性(即服務的持續可用性)。
在默認情況下Eureka server就工作在Peer-aware模式下,所以一個Eureka server也是一個Eureka client,並把自己的信息注冊到一個peer中。
這也是在生產環境下Eureka的常用模式,在單機模式下,如在測試或者為了了解原理時,可以將registerWithEureka設置成false。
2.當一個Eureka server啟動時,它將嘗試從其他的peer 節點中獲取注冊信息。
對於每一個peer節點,這個操作最多會嘗試5次(通過eureka.server.numberRegistrySyncRetries配置),如果這個操作失敗,這個server會在5min內(通過eureka.server.getWaitTimeInMsWhenSyncEmpty配置)阻止其他客戶端從自己這里獲取注冊信息。
3.Eureka peer-aware模式引入了“self-preservation”的概念,這也將Eureka的復雜度提升了一個級別(可以通過將eureka.server.enableSelfPreservation設置成false來關閉此功能)。
以下摘自Netflix的描述
4.具體數學邏輯如下:
假定有兩個client注冊到Eureka server,每個client每30s發送一次心跳,則server需要一分鍾收到4次心跳。spring 在此基礎上追加了一個最小心跳值1(通過eureka.instance.registry.expectedNumberOfRenewsPerMin設置),如此一來,最小的心跳數變成了5,然后這個值還需要乘以最小閾值百分比0.85(eureka.server.renewalPercentThreshold),並近似為比本身大的最小整數 5*0.85=4.25 -->5。此閾值每15分鍾才會更新一次(通過eureka.server.renewalThresholdUpdateIntervalMs設置),因此在這15分鍾內的任何時間點server收到的心跳數低於5次,這個server就進入self-preservation模式,並停止移除instance信息。
5.Eureka server假定每一個client都是以每30s一次的固定頻率發送心跳。如果注冊了兩個client,server就期望一分鍾收到(2+2+1)*0.85=5 次心跳,如果收到的次數比這個值小,就會激活self-preservation模式。假定現在每一個client發送心跳都加快(10s一次),server在一分鍾內就會收到12次,即便有一個服務down掉,還能收到6次,仍然大於期望的5次,如此就不會觸發原本應該觸發的self-preservation模式,這也是為什么官方不建議修改eureka.instance.leaseRenewalIntervalInSeconds值。
6.另外還需要注意,不做特殊配置在同一個host上無法同時運行多個Eureka server。在com.netflix.eureka.cluster.PeerEurekaNodes.isThisMyUrl方法中利用host過濾掉了peer URLs,這個可能是為了防止一個server注冊成為自己的peer,但是這個方法沒有檢查port,只有當hostname不同時peer 模式才能正常工作,所以想在一個主機上驗證peer-aware模式,需要配置自己的/etc/hosts文件。
因為Eureka已為我們做了過濾,所以在做Eureka群集時所有Eureka server的serviceUrl都可以設置的一樣,不用再排除自己