自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

開發(fā) 架構(gòu)
微服務(wù)架構(gòu)中最核心的部分是服務(wù)治理,服務(wù)治理最基礎(chǔ)的組件是注冊中心。隨著微服務(wù)架構(gòu)的發(fā)展,出現(xiàn)了很多微服務(wù)架構(gòu)的解決方案,其中包括我們熟知的 Dubbo 和 Spring Cloud。

 微服務(wù)架構(gòu)中最核心的部分是服務(wù)治理,服務(wù)治理最基礎(chǔ)的組件是注冊中心。隨著微服務(wù)架構(gòu)的發(fā)展,出現(xiàn)了很多微服務(wù)架構(gòu)的解決方案,其中包括我們熟知的 Dubbo 和 Spring Cloud。

[[274721]]

關(guān)于注冊中心的解決方案,dubbo 支持了 Zookeeper、Redis、Multicast 和 Simple,官方推薦 Zookeeper。Spring Cloud 支持了 Zookeeper、Consul 和 Eureka,官方推薦 Eureka。

兩者之所以推薦不同的實(shí)現(xiàn)方式,原因在于組件的特點(diǎn)以及適用場景不同。簡單來說:

  • ZK 的設(shè)計(jì)原則是 CP,即強(qiáng)一致性和分區(qū)容錯(cuò)性。他保證數(shù)據(jù)的強(qiáng)一致性,但舍棄了可用性,如果出現(xiàn)網(wǎng)絡(luò)問題可能會影響 ZK 的選舉,導(dǎo)致 ZK 注冊中心的不可用。
  • Eureka 的設(shè)計(jì)原則是 AP,即可用性和分區(qū)容錯(cuò)性。他保證了注冊中心的可用性,但舍棄了數(shù)據(jù)一致性,各節(jié)點(diǎn)上的數(shù)據(jù)有可能是不一致的(會最終一致)。
  • Eureka 采用純 Java 實(shí)現(xiàn),除實(shí)現(xiàn)了注冊中心基本的服務(wù)注冊和發(fā)現(xiàn)之外,極大的滿足注冊中心的可用性,即使只有一臺服務(wù)可用,也可以保證注冊中心的可用性。
  • 本文將聚焦到 Eureka 的內(nèi)部實(shí)現(xiàn)原理,先從微服務(wù)架構(gòu)的部署圖介紹 Eureka 的總體架構(gòu),然后剖析服務(wù)信息的存儲結(jié)構(gòu),最后探究跟服務(wù)生命周期相關(guān)的服務(wù)注冊機(jī)制、服務(wù)續(xù)約機(jī)制、服務(wù)注銷機(jī)制、服務(wù)剔除機(jī)制、服務(wù)獲取機(jī)制、和服務(wù)同步機(jī)制。

Eureka 總體架構(gòu)

下面是 Eureka 注冊中心部署在多個(gè)機(jī)房的架構(gòu)圖,這正是他高可用性的優(yōu)勢(Zookeeper 千萬別這么部署)。

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

從組件功能看:

  • 黃色注冊中心集群,分別部署在北京、天津、青島機(jī)房;
  • 紅色服務(wù)提供者,分別部署北京和青島機(jī)房;
  • 淡綠色服務(wù)消費(fèi)者,分別部署在北京和天津機(jī)房;

從機(jī)房分布看:

  • 北京機(jī)房部署了注冊中心、服務(wù)提供者和服務(wù)消費(fèi)者;
  • 天津機(jī)房部署了注冊中心和服務(wù)消費(fèi)者;
  • 青島機(jī)房部署了注冊中心和服務(wù)提供者;

組件調(diào)用關(guān)系

服務(wù)提供者

  • 啟動后,向注冊中心發(fā)起 register 請求,注冊服務(wù)
  • 在運(yùn)行過程中,定時(shí)向注冊中心發(fā)送 renew 心跳,證明“我還活著”。
  • 停止服務(wù)提供者,向注冊中心發(fā)起 cancel 請求,清空當(dāng)前服務(wù)注冊信息。

服務(wù)消費(fèi)者

  1. 啟動后,從注冊中心拉取服務(wù)注冊信息
  2. 在運(yùn)行過程中,定時(shí)更新服務(wù)注冊信息。
  3. 服務(wù)消費(fèi)者發(fā)起遠(yuǎn)程調(diào)用:
  4. a> 服務(wù)消費(fèi)者(北京)會從服務(wù)注冊信息中選擇同機(jī)房的服務(wù)提供者(北京),發(fā)起遠(yuǎn)程調(diào)用。只有同機(jī)房的服務(wù)提供者掛了才會選擇其他機(jī)房的服務(wù)提供者(青島)。
  5. b> 服務(wù)消費(fèi)者(天津)因?yàn)橥瑱C(jī)房內(nèi)沒有服務(wù)提供者,則會按負(fù)載均衡算法選擇北京或青島的服務(wù)提供者,發(fā)起遠(yuǎn)程調(diào)用。

注冊中心

啟動后,從其他節(jié)點(diǎn)拉取服務(wù)注冊信息。

運(yùn)行過程中,定時(shí)運(yùn)行 evict 任務(wù),剔除沒有按時(shí) renew 的服務(wù)(包括非正常停止和網(wǎng)絡(luò)故障的服務(wù))。

運(yùn)行過程中,接收到的 register、renew、cancel 請求,都會同步至其他注冊中心節(jié)點(diǎn)。

本文將詳細(xì)說明上圖中的 registry、register、renew、cancel、getRegistry、evict 的內(nèi)部機(jī)制。

數(shù)據(jù)存儲結(jié)構(gòu)

既然是服務(wù)注冊中心,必然要存儲服務(wù)的信息,我們知道 ZK 是將服務(wù)信息保存在樹形節(jié)點(diǎn)上。而下面是 Eureka 的數(shù)據(jù)存儲結(jié)構(gòu):

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

Eureka 的數(shù)據(jù)存儲分了兩層:數(shù)據(jù)存儲層和緩存層。

Eureka Client 在拉取服務(wù)信息時(shí),先從緩存層獲取(相當(dāng)于 Redis),如果獲取不到,先把數(shù)據(jù)存儲層的數(shù)據(jù)加載到緩存中(相當(dāng)于 Mysql),再從緩存中獲取。值得注意的是,數(shù)據(jù)存儲層的數(shù)據(jù)結(jié)構(gòu)是服務(wù)信息,而緩存中保存的是經(jīng)過處理加工過的、可以直接傳輸?shù)?Eureka Client 的數(shù)據(jù)結(jié)構(gòu)。

Eureka 這樣的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)是把內(nèi)部的數(shù)據(jù)存儲結(jié)構(gòu)與對外的數(shù)據(jù)結(jié)構(gòu)隔離開了,就像是我們平時(shí)在進(jìn)行接口設(shè)計(jì)一樣,對外輸出的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)庫中的數(shù)據(jù)結(jié)構(gòu)往往都是不一樣的。

數(shù)據(jù)存儲層

這里為什么說是存儲層而不是持久層?因?yàn)?rigistry 本質(zhì)上是一個(gè)雙層的 ConcurrentHashMap,存儲在內(nèi)存中的。

  • 第一層的 key 是spring.application.name,value 是第二層 ConcurrentHashMap;
  • 第二層 ConcurrentHashMap 的 key 是服務(wù)的 InstanceId,value 是 Lease 對象;
  • Lease 對象包含了服務(wù)詳情和服務(wù)治理相關(guān)的屬性。

二級緩存層

Eureka 實(shí)現(xiàn)了二級緩存來保存即將要對外傳輸?shù)姆?wù)信息,數(shù)據(jù)結(jié)構(gòu)完全相同。

  • 一級緩存:ConcurrentHashMap<Key,Value> readOnlyCacheMap,本質(zhì)上是 HashMap,無過期時(shí)間,保存服務(wù)信息的對外輸出數(shù)據(jù)結(jié)構(gòu)。
  • 二級緩存:Loading<Key,Value> readWriteCacheMap,本質(zhì)上是 guava 的緩存,包含失效機(jī)制,保存服務(wù)信息的對外輸出數(shù)據(jù)結(jié)構(gòu)。

既然是緩存,那必然要有更新機(jī)制,來保證數(shù)據(jù)的一致性。下面是緩存的更新機(jī)制:

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

更新機(jī)制包含刪除和加載兩個(gè)部分,上圖黑色箭頭表示刪除緩存的動作,綠色表示加載或觸發(fā)加載的動作。

刪除二級緩存:

Eureka Client 發(fā)送 register、renew 和 cancel 請求并更新 registry 注冊表之后,刪除二級緩存;

Eureka Server 自身的 Evict Task 剔除服務(wù)后,刪除二級緩存;

二級緩存本身設(shè)置了 guava 的失效機(jī)制,隔一段時(shí)間后自己自動失效;

加載二級緩存:

Eureka Client 發(fā)送 getRegistry 請求后,如果二級緩存中沒有,就觸發(fā) guava 的 load,即從 registry 中獲取原始服務(wù)信息后進(jìn)行處理加工,再加載到二級緩存中。

Eureka Server 更新一級緩存的時(shí)候,如果二級緩存沒有數(shù)據(jù),也會觸發(fā) guava 的 load。

更新一級緩存:

  • Eureka Server 內(nèi)置了一個(gè) TimerTask,定時(shí)將二級緩存中的數(shù)據(jù)同步到一級緩存(這個(gè)動作包括了刪除和加載)。
  • 關(guān)于緩存的實(shí)現(xiàn)參考 ResponseCacheImpl

服務(wù)注冊機(jī)制

服務(wù)提供者、服務(wù)消費(fèi)者、以及服務(wù)注冊中心自己,啟動后都會向注冊中心注冊服務(wù)(如果配置了注冊)。下圖是介紹如何完成服務(wù)注冊的:

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

注冊中心服務(wù)接收到 register 請求后:

  • 保存服務(wù)信息,將服務(wù)信息保存到 registry 中;
  • 更新隊(duì)列,將此事件添加到更新隊(duì)列中,供 Eureka Client 增量同步服務(wù)信息使用。
  • 清空二級緩存,即 readWriteCacheMap,用于保證數(shù)據(jù)的一致性。
  • 更新閾值,供剔除服務(wù)使用。
  • 同步服務(wù)信息,將此事件同步至其他的 Eureka Server 節(jié)點(diǎn)。

服務(wù)續(xù)約機(jī)制

服務(wù)注冊后,要定時(shí)(默認(rèn) 30S,可自己配置)向注冊中心發(fā)送續(xù)約請求,告訴注冊中心“我還活著”。

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

注冊中心收到續(xù)約請求后:

  • 更新服務(wù)對象的最近續(xù)約時(shí)間,即 Lease 對象的 lastUpdateTimestamp;
  • 同步服務(wù)信息,將此事件同步至其他的 Eureka Server 節(jié)點(diǎn)。
  • 剔除服務(wù)之前會先判斷服務(wù)是否已經(jīng)過期,判斷服務(wù)是否過期的條件之一是續(xù)約時(shí)間和當(dāng)前時(shí)間的差值是不是大于閾值。

服務(wù)注銷機(jī)制

服務(wù)正常停止之前會向注冊中心發(fā)送注銷請求,告訴注冊中心“我要下線了”。

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

注冊中心服務(wù)接收到 cancel 請求后:

  • 刪除服務(wù)信息,將服務(wù)信息從 registry 中刪除;
  • 更新隊(duì)列,將此事件添加到更新隊(duì)列中,供 Eureka Client 增量同步服務(wù)信息使用。
  • 清空二級緩存,即 readWriteCacheMap,用于保證數(shù)據(jù)的一致性。
  • 更新閾值,供剔除服務(wù)使用。
  • 同步服務(wù)信息,將此事件同步至其他的 Eureka Server 節(jié)點(diǎn)。
  • 服務(wù)正常停止才會發(fā)送 Cancel,如果是非正常停止,則不會發(fā)送,此服務(wù)由 Eureka Server 主動剔除。

服務(wù)剔除機(jī)制

Eureka Server 提供了服務(wù)剔除的機(jī)制,用于剔除沒有正常下線的服務(wù)。

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

服務(wù)的剔除包括三個(gè)步驟,首先判斷是否滿足服務(wù)剔除的條件,然后找出過期的服務(wù),最后執(zhí)行剔除。

判斷是否滿足服務(wù)剔除的條件

有兩種情況可以滿足服務(wù)剔除的條件:

  • 關(guān)閉了自我保護(hù)
  • 如果開啟了自我保護(hù),需要進(jìn)一步判斷是 Eureka Server 出了問題,還是 Eureka Client 出了問題,如果是 Eureka Client 出了問題則進(jìn)行剔除。

這里比較核心的條件是自我保護(hù)機(jī)制,Eureka 自我保護(hù)機(jī)制是為了防止誤殺服務(wù)而提供的一個(gè)機(jī)制。Eureka 的自我保護(hù)機(jī)制“謙虛”的認(rèn)為如果大量服務(wù)都續(xù)約失敗,則認(rèn)為是自己出問題了(如自己斷網(wǎng)了),也就不剔除了;反之,則是 Eureka Client 的問題,需要進(jìn)行剔除。而自我保護(hù)閾值是區(qū)分 Eureka Client 還是 Eureka Server 出問題的臨界值:如果超出閾值就表示大量服務(wù)可用,少量服務(wù)不可用,則判定是 Eureka Client 出了問題。如果未超出閾值就表示大量服務(wù)不可用,則判定是 Eureka Server 出了問題。

條件 1 中如果關(guān)閉了自我保護(hù),則統(tǒng)統(tǒng)認(rèn)為是 Eureka Client 的問題,把沒按時(shí)續(xù)約的服務(wù)都剔除掉(這里有剔除的最大值限制)。

這里比較難理解的是閾值的計(jì)算:

  • 自我保護(hù)閾值 = 服務(wù)總數(shù) * 每分鐘續(xù)約數(shù) * 自我保護(hù)閾值因子。
  • 每分鐘續(xù)約數(shù) =(60S/ 客戶端續(xù)約間隔)

最后自我保護(hù)閾值的計(jì)算公式為:

自我保護(hù)閾值 = 服務(wù)總數(shù) * (60S/ 客戶端續(xù)約間隔) * 自我保護(hù)閾值因子。

舉例:如果有 100 個(gè)服務(wù),續(xù)約間隔是 30S,自我保護(hù)閾值 0.85。

自我保護(hù)閾值 =100 * 60 / 30 * 0.85 = 170。

如果上一分鐘的續(xù)約數(shù) =180>170,則說明大量服務(wù)可用,是服務(wù)問題,進(jìn)入剔除流程;

如果上一分鐘的續(xù)約數(shù) =150<170,則說明大量服務(wù)不可用,是注冊中心自己的問題,進(jìn)入自我保護(hù)模式,不進(jìn)入剔除流程。

找出過期的服務(wù)

遍歷所有的服務(wù),判斷上次續(xù)約時(shí)間距離當(dāng)前時(shí)間大于閾值就標(biāo)記為過期。并將這些過期的服務(wù)保存到集合中。

剔除服務(wù)

在剔除服務(wù)之前先計(jì)算剔除的數(shù)量,然后遍歷過期服務(wù),通過洗牌算法確保每次都公平的選擇出要剔除的任務(wù),最后進(jìn)行剔除。

執(zhí)行剔除服務(wù)后:

  • 刪除服務(wù)信息,從 registry 中刪除服務(wù)。
  • 更新隊(duì)列,將當(dāng)前剔除事件保存到更新隊(duì)列中。
  • 清空二級緩存,保證數(shù)據(jù)的一致性。
  • 實(shí)現(xiàn)過程參考 AbstractInstanceRegistry.evict() 方法。

服務(wù)獲取機(jī)制

Eureka Client 獲取服務(wù)有兩種方式,全量同步和增量同步。獲取流程是根據(jù) Eureka Server 的多層數(shù)據(jù)結(jié)構(gòu)進(jìn)行的:

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

無論是全量同步還是增量同步,都是先從緩存中獲取,如果緩存中沒有,則先加載到緩存中,再從緩存中獲取。(registry 只保存數(shù)據(jù)結(jié)構(gòu),緩存中保存 ready 的服務(wù)信息。)

  • 先從一級緩存中獲取
  • a> 先判斷是否開啟了一級緩存
  • b> 如果開啟了則從一級緩存中獲取,如果存在則返回,如果沒有,則從二級緩存中獲取
  • d> 如果未開啟,則跳過一級緩存,從二級緩存中獲取
  • 再從二級緩存中獲取
  • a> 如果二級緩存中存在,則直接返回;
  • b> 如果二級緩存中不存在,則先將數(shù)據(jù)加載到二級緩存中,再從二級緩存中獲取。注意加載時(shí)需要判斷是增量同步還是全量同步,增量同步從 recentlyChangedQueue 中 load,全量同步從 registry 中 load。

服務(wù)同步機(jī)制

服務(wù)同步機(jī)制是用來同步 Eureka Server 節(jié)點(diǎn)之間服務(wù)信息的。它包括 Eureka Server 啟動時(shí)的同步,和運(yùn)行過程中的同步。

啟動時(shí)同步

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

Eureka Server 啟動后,遍歷 eurekaClient.getApplications 獲取服務(wù)信息,并將服務(wù)信息注冊到自己的 registry 中。

注意這里是兩層循環(huán),第一層循環(huán)是為了保證已經(jīng)拉取到服務(wù)信息,第二層循環(huán)是遍歷拉取到的服務(wù)信息。

運(yùn)行過程中同步

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

當(dāng) Eureka Server 節(jié)點(diǎn)有 register、renew、cancel 請求進(jìn)來時(shí),會將這個(gè)請求封裝成 TaskHolder 放到 acceptorQueue 隊(duì)列中,然后經(jīng)過一系列的處理,放到 batchWorkQueue 中。

TaskExecutor.BatchWorkerRunnable是個(gè)線程池,不斷的從 batchWorkQueue 隊(duì)列中 poll 出 TaskHolder,然后向其他 Eureka Server 節(jié)點(diǎn)發(fā)送同步請求。

這里省略了兩個(gè)部分:

一個(gè)是在 acceptorQueue 向 batchWorkQueue 轉(zhuǎn)化時(shí),省略了中間的 processingOrder 和 pendingTasks 過程。

另一個(gè)是當(dāng)同步失敗時(shí),會將失敗的 TaskHolder 保存到 reprocessQueue 中,重試處理。

寫在最后

對微服務(wù)解決方案 Dubbo 和 Spring Cloud 的對比非常多,這里對注冊中心做個(gè)簡單對比。

微服務(wù)注冊中心 Eureka 架構(gòu)深入解讀

ZookeeperEureka設(shè)計(jì)原則CPAP優(yōu)點(diǎn)數(shù)據(jù)強(qiáng)一致服務(wù)高可用缺點(diǎn)網(wǎng)絡(luò)分區(qū)會影響 Leader 選舉,超過閾值后集群不可用服務(wù)節(jié)點(diǎn)間的數(shù)據(jù)可能不一致; Client-Server 間的數(shù)據(jù)可能不一致;適用場景單機(jī)房集群,對數(shù)據(jù)一致性要求較高云機(jī)房集群,跨越多機(jī)房部署;對注冊中心服務(wù)可用性要求較高。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2025-03-31 08:35:00

Eureka微服務(wù)架構(gòu)

2020-06-29 07:58:18

ZooKeeperConsul 注冊中心

2017-06-25 13:33:25

Spring Clou微服務(wù)架構(gòu)

2024-12-03 10:55:56

微服務(wù)架構(gòu)注冊中心

2017-07-03 08:29:42

Spring Clou服務(wù)詳解

2024-11-21 16:09:22

2022-07-17 06:54:51

Eureka架構(gòu)

2020-01-10 10:58:34

ZooKeeperEureka注冊中心

2021-04-28 08:05:30

SpringCloudEureka服務(wù)注冊

2023-04-28 07:52:14

CAPEureka注冊中心

2022-11-18 17:36:38

Spring架構(gòu)

2021-04-20 17:20:59

SpringColud EurekaNetflix開發(fā)

2021-01-04 09:35:55

微服務(wù)架構(gòu)配置中心

2021-03-17 10:51:16

架構(gòu)運(yùn)維技術(shù)

2023-06-20 08:59:25

微服務(wù)注冊中心運(yùn)維

2023-07-28 09:23:24

微服務(wù)架構(gòu)

2023-04-26 08:19:48

Nacos高可用開發(fā)

2023-06-02 08:33:43

微服務(wù)架構(gòu)服務(wù)注冊

2024-07-10 10:51:39

SpringEureka數(shù)據(jù)中心

2024-12-19 10:48:12

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號