來深入了解一下 Eureka 的工作機(jī)制及相關(guān)原理
點(diǎn)擊上方藍(lán)色“程序猿DD”,選擇“設(shè)為星標(biāo)”
回復(fù)“資源”獲取獨(dú)家整理的學(xué)習(xí)資料!

Eureka 工作原理
我們來學(xué)習(xí) Eureka,了解它的相關(guān)概念、工作流程機(jī)制等。
Eureka 作為 Spring Cloud 體系中最核心、默認(rèn)的注冊(cè)中心組件,研究它的運(yùn)行機(jī)制,有助于我們?cè)诠ぷ髦懈玫厥褂盟?/p>
Eureka 核心概念
回到上節(jié)的服務(wù)注冊(cè)調(diào)用示意圖,服務(wù)提供者和服務(wù)的消費(fèi)者,本質(zhì)上也是 Eureka Client 角色。整體上可以分為兩個(gè)主體:Eureka Server 和 Eureka Client。

Eureka Server:注冊(cè)中心服務(wù)端
注冊(cè)中心服務(wù)端主要對(duì)外提供了三個(gè)功能:
-
服務(wù)注冊(cè)
服務(wù)提供者啟動(dòng)時(shí),會(huì)通過 Eureka Client 向 Eureka Server 注冊(cè)信息,Eureka Server 會(huì)存儲(chǔ)該服務(wù)的信息,Eureka Server 內(nèi)部有二層緩存機(jī)制來維護(hù)整個(gè)注冊(cè)表
-
提供注冊(cè)表
服務(wù)消費(fèi)者在調(diào)用服務(wù)時(shí),如果 Eureka Client 沒有緩存注冊(cè)表的話,會(huì)從 Eureka Server 獲取最新的注冊(cè)表
-
同步狀態(tài)
Eureka Client 通過注冊(cè)、心跳機(jī)制和 Eureka Server 同步當(dāng)前客戶端的狀態(tài)。
Eureka Client:注冊(cè)中心客戶端
Eureka Client 是一個(gè) Java 客戶端,用于簡(jiǎn)化與 Eureka Server 的交互。Eureka Client 會(huì)拉取、更新和緩存 Eureka Server 中的信息。因此當(dāng)所有的 Eureka Server 節(jié)點(diǎn)都宕掉,服務(wù)消費(fèi)者依然可以使用緩存中的信息找到服務(wù)提供者,但是當(dāng)服務(wù)有更改的時(shí)候會(huì)出現(xiàn)信息不一致。
Register: 服務(wù)注冊(cè)
服務(wù)的提供者,將自身注冊(cè)到注冊(cè)中心,服務(wù)提供者也是一個(gè) Eureka Client。當(dāng) Eureka Client 向 Eureka Server 注冊(cè)時(shí),它提供自身的元數(shù)據(jù),比如 IP 地址、端口,運(yùn)行狀況指示符 URL,主頁等。
Renew: 服務(wù)續(xù)約
Eureka Client 會(huì)每隔 30 秒發(fā)送一次心跳來續(xù)約。通過續(xù)約來告知 Eureka Server 該 Eureka Client 運(yùn)行正常,沒有出現(xiàn)問題。默認(rèn)情況下,如果 Eureka Server 在 90 秒內(nèi)沒有收到 Eureka Client 的續(xù)約,Server 端會(huì)將實(shí)例從其注冊(cè)表中刪除,此時(shí)間可配置,一般情況不建議更改。
服務(wù)續(xù)約的兩個(gè)重要屬性
# 服務(wù)續(xù)約任務(wù)的調(diào)用間隔時(shí)間,默認(rèn)為30秒
eureka.instance.lease-renewal-interval-in-seconds=30
# 服務(wù)失效的時(shí)間,默認(rèn)為90秒。
eureka.instance.lease-expiration-duration-in-seconds=90
Eviction 服務(wù)剔除
當(dāng) Eureka Client 和 Eureka Server 不再有心跳時(shí),Eureka Server 會(huì)將該服務(wù)實(shí)例從服務(wù)注冊(cè)列表中刪除,即服務(wù)剔除。
Cancel: 服務(wù)下線
Eureka Client 在程序關(guān)閉時(shí)向 Eureka Server 發(fā)送取消請(qǐng)求。發(fā)送請(qǐng)求后,該客戶端實(shí)例信息將從 Eureka Server 的實(shí)例注冊(cè)表中刪除。該下線請(qǐng)求不會(huì)自動(dòng)完成,它需要調(diào)用以下內(nèi)容:
DiscoveryManager.getInstance().shutdownComponent();
GetRegisty: 獲取注冊(cè)列表信息
Eureka Client 從服務(wù)器獲取注冊(cè)表信息,并將其緩存在本地。客戶端會(huì)使用該信息查找其他服務(wù),從而進(jìn)行遠(yuǎn)程調(diào)用。該注冊(cè)列表信息定期(每30秒鐘)更新一次。每次返回注冊(cè)列表信息可能與 Eureka Client 的緩存信息不同,Eureka Client 自動(dòng)處理。
如果由于某種原因?qū)е伦?cè)列表信息不能及時(shí)匹配,Eureka Client 則會(huì)重新獲取整個(gè)注冊(cè)表信息。Eureka Server 緩存注冊(cè)列表信息,整個(gè)注冊(cè)表以及每個(gè)應(yīng)用程序的信息進(jìn)行了壓縮,壓縮內(nèi)容和沒有壓縮的內(nèi)容完全相同。
Eureka Client 和 Eureka Server 可以使用 JSON/XML 格式進(jìn)行通訊。在默認(rèn)情況下 Eureka Client 使用壓縮 JSON 格式來獲取注冊(cè)列表的信息。
獲取服務(wù)是服務(wù)消費(fèi)者的基礎(chǔ),所以必有兩個(gè)重要參數(shù)需要注意:
# 啟用服務(wù)消費(fèi)者從注冊(cè)中心拉取服務(wù)列表的功能
eureka.client.fetch-registry=true
# 設(shè)置服務(wù)消費(fèi)者從注冊(cè)中心拉取服務(wù)列表的間隔
eureka.client.registry-fetch-interval-seconds=30
Remote Call: 遠(yuǎn)程調(diào)用
當(dāng) Eureka Client 從注冊(cè)中心獲取到服務(wù)提供者信息后,就可以通過 Http 請(qǐng)求調(diào)用對(duì)應(yīng)的服務(wù);服務(wù)提供者有多個(gè)時(shí),Eureka Client 客戶端會(huì)通過 Ribbon 自動(dòng)進(jìn)行負(fù)載均衡。強(qiáng)烈推薦:100道Java中高級(jí)面試題匯總+詳細(xì)拆解
自我保護(hù)機(jī)制
默認(rèn)情況下,如果 Eureka Server 在一定的 90s 內(nèi)沒有接收到某個(gè)微服務(wù)實(shí)例的心跳,會(huì)注銷該實(shí)例。但是在微服務(wù)架構(gòu)下服務(wù)之間通常都是跨進(jìn)程調(diào)用,網(wǎng)絡(luò)通信往往會(huì)面臨著各種問題,比如微服務(wù)狀態(tài)正常,網(wǎng)絡(luò)分區(qū)故障,導(dǎo)致此實(shí)例被注銷。
固定時(shí)間內(nèi)大量實(shí)例被注銷,可能會(huì)嚴(yán)重威脅整個(gè)微服務(wù)架構(gòu)的可用性。為了解決這個(gè)問題,Eureka 開發(fā)了自我保護(hù)機(jī)制,那么什么是自我保護(hù)機(jī)制呢?
Eureka Server 在運(yùn)行期間會(huì)去統(tǒng)計(jì)心跳失敗比例在 15 分鐘之內(nèi)是否低于 85%,如果低于 85%,Eureka Server 即會(huì)進(jìn)入自我保護(hù)機(jī)制。
Eureka Server 觸發(fā)自我保護(hù)機(jī)制后,頁面會(huì)出現(xiàn)提示:

Eureka Server 進(jìn)入自我保護(hù)機(jī)制,會(huì)出現(xiàn)以下幾種情況:
-
Eureka 不再從注冊(cè)列表中移除因?yàn)殚L(zhǎng)時(shí)間沒收到心跳而應(yīng)該過期的服務(wù) -
Eureka 仍然能夠接受新服務(wù)的注冊(cè)和查詢請(qǐng)求,但是不會(huì)被同步到其它節(jié)點(diǎn)上(即保證當(dāng)前節(jié)點(diǎn)依然可用) -
當(dāng)網(wǎng)絡(luò)穩(wěn)定時(shí),當(dāng)前實(shí)例新的注冊(cè)信息會(huì)被同步到其它節(jié)點(diǎn)中
Eureka 自我保護(hù)機(jī)制是為了防止誤殺服務(wù)而提供的一個(gè)機(jī)制。當(dāng)個(gè)別客戶端出現(xiàn)心跳失聯(lián)時(shí),則認(rèn)為是客戶端的問題,剔除掉客戶端;當(dāng) Eureka 捕獲到大量的心跳失敗時(shí),則認(rèn)為可能是網(wǎng)絡(luò)問題,進(jìn)入自我保護(hù)機(jī)制;當(dāng)客戶端心跳恢復(fù)時(shí),Eureka 會(huì)自動(dòng)退出自我保護(hù)機(jī)制。
如果在保護(hù)期內(nèi)剛好這個(gè)服務(wù)提供者非正常下線了,此時(shí)服務(wù)消費(fèi)者就會(huì)拿到一個(gè)無效的服務(wù)實(shí)例,即會(huì)調(diào)用失敗。對(duì)于這個(gè)問題需要服務(wù)消費(fèi)者端要有一些容錯(cuò)機(jī)制,如重試,斷路器等。
通過在 Eureka Server 配置如下參數(shù),開啟或者關(guān)閉保護(hù)機(jī)制,生產(chǎn)環(huán)境建議打開:
eureka.server.enable-self-preservation=true
Eureka 集群原理
再來看看 Eureka 集群的工作原理。我們假設(shè)有三臺(tái) Eureka Server 組成的集群,第一臺(tái) Eureka Server 在北京機(jī)房,另外兩臺(tái) Eureka Server 在深圳和西安機(jī)房。
這樣三臺(tái) Eureka Server 就組建成了一個(gè)跨區(qū)域的高可用集群,只要三個(gè)地方的任意一個(gè)機(jī)房不出現(xiàn)問題,都不會(huì)影響整個(gè)架構(gòu)的穩(wěn)定性。

從圖中可以看出 Eureka Server 集群相互之間通過 Replicate 來同步數(shù)據(jù),相互之間不區(qū)分主節(jié)點(diǎn)和從節(jié)點(diǎn),所有的節(jié)點(diǎn)都是平等的。在這種架構(gòu)中,節(jié)點(diǎn)通過彼此互相注冊(cè)來提高可用性,每個(gè)節(jié)點(diǎn)需要添加一個(gè)或多個(gè)有效的 serviceUrl 指向其他節(jié)點(diǎn)。
如果某臺(tái) Eureka Server 宕機(jī),Eureka Client 的請(qǐng)求會(huì)自動(dòng)切換到新的 Eureka Server 節(jié)點(diǎn)。當(dāng)宕機(jī)的服務(wù)器重新恢復(fù)后,Eureka 會(huì)再次將其納入到服務(wù)器集群管理之中。當(dāng)節(jié)點(diǎn)開始接受客戶端請(qǐng)求時(shí),所有的操作都會(huì)進(jìn)行節(jié)點(diǎn)間復(fù)制,將請(qǐng)求復(fù)制到其它 Eureka Server 當(dāng)前所知的所有節(jié)點(diǎn)中。
另外 Eureka Server 的同步遵循著一個(gè)非常簡(jiǎn)單的原則:只要有一條邊將節(jié)點(diǎn)連接,就可以進(jìn)行信息傳播與同步。所以,如果存在多個(gè)節(jié)點(diǎn),只需要將節(jié)點(diǎn)之間兩兩連接起來形成通路,那么其它注冊(cè)中心都可以共享信息。每個(gè) Eureka Server 同時(shí)也是 Eureka Client,多個(gè) Eureka Server 之間通過 P2P 的方式完成服務(wù)注冊(cè)表的同步。
Eureka Server 集群之間的狀態(tài)是采用異步方式同步的,所以不保證節(jié)點(diǎn)間的狀態(tài)一定是一致的,不過基本能保證最終狀態(tài)是一致的。
Eureka 分區(qū)
Eureka 提供了 Region 和 Zone 兩個(gè)概念來進(jìn)行分區(qū),這兩個(gè)概念均來自于亞馬遜的 AWS:
-
region:可以理解為地理上的不同區(qū)域,比如亞洲地區(qū),中國(guó)區(qū)或者深圳等等。沒有具體大小的限制。根據(jù)項(xiàng)目具體的情況,可以自行合理劃分 region。
-
zone:可以簡(jiǎn)單理解為 region 內(nèi)的具體機(jī)房,比如說 region 劃分為深圳,然后深圳有兩個(gè)機(jī)房,就可以在此 region 之下劃分出 zone1、zone2 兩個(gè) zone。
上圖中的 us-east-1c、us-east-1d、us-east-1e 就代表了不同的 Zone。Zone 內(nèi)的 Eureka Client 優(yōu)先和 Zone 內(nèi)的 Eureka Server 進(jìn)行心跳同步,同樣調(diào)用端優(yōu)先在 Zone 內(nèi)的 Eureka Server 獲取服務(wù)列表,當(dāng) Zone 內(nèi)的 Eureka Server 掛掉之后,才會(huì)從別的 Zone 中獲取信息。
Eurka 保證 AP
Eureka Server 各個(gè)節(jié)點(diǎn)都是平等的,幾個(gè)節(jié)點(diǎn)掛掉不會(huì)影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊(cè)和查詢服務(wù)。而 Eureka Client 在向某個(gè) Eureka 注冊(cè)時(shí),如果發(fā)現(xiàn)連接失敗,則會(huì)自動(dòng)切換至其它節(jié)點(diǎn)。只要有一臺(tái) Eureka Server 還在,就能保證注冊(cè)服務(wù)可用(保證可用性),只不過查到的信息可能不是最新的(不保證強(qiáng)一致性)。強(qiáng)烈推薦:100道Java中高級(jí)面試題匯總+詳細(xì)拆解
Eurka 工作流程
了解完 Eureka 核心概念,自我保護(hù)機(jī)制,以及集群內(nèi)的工作原理后,我們來整體梳理一下 Eureka 的工作流程:
1、Eureka Server 啟動(dòng)成功,等待服務(wù)端注冊(cè)。在啟動(dòng)過程中如果配置了集群,集群之間定時(shí)通過 Replicate 同步注冊(cè)表,每個(gè) Eureka Server 都存在獨(dú)立完整的服務(wù)注冊(cè)表信息
2、Eureka Client 啟動(dòng)時(shí)根據(jù)配置的 Eureka Server 地址去注冊(cè)中心注冊(cè)服務(wù)
3、Eureka Client 會(huì)每 30s 向 Eureka Server 發(fā)送一次心跳請(qǐng)求,證明客戶端服務(wù)正常
4、當(dāng) Eureka Server 90s 內(nèi)沒有收到 Eureka Client 的心跳,注冊(cè)中心則認(rèn)為該節(jié)點(diǎn)失效,會(huì)注銷該實(shí)例
5、單位時(shí)間內(nèi) Eureka Server 統(tǒng)計(jì)到有大量的 Eureka Client 沒有上送心跳,則認(rèn)為可能為網(wǎng)絡(luò)異常,進(jìn)入自我保護(hù)機(jī)制,不再剔除沒有上送心跳的客戶端
6、當(dāng) Eureka Client 心跳請(qǐng)求恢復(fù)正常之后,Eureka Server 自動(dòng)退出自我保護(hù)模式
7、Eureka Client 定時(shí)全量或者增量從注冊(cè)中心獲取服務(wù)注冊(cè)表,并且將獲取到的信息緩存到本地
8、服務(wù)調(diào)用時(shí),Eureka Client 會(huì)先從本地緩存找尋調(diào)取的服務(wù)。如果獲取不到,先從注冊(cè)中心刷新注冊(cè)表,再同步到本地緩存
9、Eureka Client 獲取到目標(biāo)服務(wù)器信息,發(fā)起服務(wù)調(diào)用
10、Eureka Client 程序關(guān)閉時(shí)向 Eureka Server 發(fā)送取消請(qǐng)求,Eureka Server 將實(shí)例從注冊(cè)表中刪除
這就是Eurka基本工作流程
總結(jié)
講了 Eureka 核心概念、Eureka 自我保護(hù)機(jī)制和 Eureka 集群原理。通過分析 Eureka 工作原理,我可以明顯地感覺到 Eureka 的設(shè)計(jì)之巧妙,通過一些列的機(jī)制,完美地解決了注冊(cè)中心的穩(wěn)定性和高可用性。
Eureka 為了保障注冊(cè)中心的高可用性,容忍了數(shù)據(jù)的非強(qiáng)一致性,服務(wù)節(jié)點(diǎn)間的數(shù)據(jù)可能不一致, Client-Server 間的數(shù)據(jù)可能不一致。比較適合跨越多機(jī)房、對(duì)注冊(cè)中心服務(wù)可用性要求較高的使用場(chǎng)景。
往期推薦
離職后與大家在星球聊了很多,你不來看看?

我的星球是否適合你?
點(diǎn)擊閱讀原文看看我們都聊過啥?
