5 種主流注冊中心技術選型,哪個最香?

講解 5 種常用的註冊中心,對比其流程和原理,無論是面試還是技術選型,都非常有幫助。

對於註冊中心,在寫這篇文章前,我其實只對 ETCD 有比較深入的瞭解,但是對於 Zookeeper 和其它的註冊中心瞭解甚少,甚至都沒有考慮過 ETCD 和 Zookeeper 是否適合作爲註冊中心。

經過近 2 周的學習,原來註冊中心除了 ETCD 和 Zookeeper,常用的還有 Eureka、Nacos、Consul,下面我們就對這些常用的註冊中心,初探它們的異同,便於後續技術選型。

註冊中心基本概念

什麼是註冊中心?

註冊中心主要有三種角色:

最後,RPC Client 從本地緩存的服務節點列表中,基於負載均衡算法選擇一臺 RPC Sever 發起調用。

註冊中心需要實現功能

根據註冊中心原理的描述,註冊中心必須實現以下功能,偷個懶,直接貼幅圖:

註冊中心基礎掃盲

這塊知識如果大家已經知道,可以直接跳過,主要是爲了掃盲。

CAP 理論

CAP 理論是分佈式架構中重要理論:

關於 P 的理解,我覺得是在整個系統中某個部分,掛掉了,或者宕機了,並不影響整個系統的運作或者說使用,而可用性是,某個系統的某個節點掛了,但是並不影響系統的接受或者發出請求。

CAP 不可能都取,只能取其中 2 個的原因如下:

分佈式系統協議

一致性協議算法主要有 Paxos、Raft、ZAB。

Paxos 算法是 Leslie Lamport 在 1990 年提出的一種基於消息傳遞的一致性算法,非常難以理解,基於 Paxos 協議的數據同步與傳統主備方式最大的區別在於:Paxos 只需超過半數的副本在線且相互通信正常,就可以保證服務的持續可用,且數據不丟失。

Raft 是斯坦福大學的 Diego Ongaro、John Ousterhout 兩個人以易理解爲目標設計的一致性算法,已經有了十幾種語言的 Raft 算法實現框架,較爲出名的有 etcd,Google 的 Kubernetes 也是用了 etcd 作爲他的服務發現框架。

Raft 是 Paxos 的簡化版,與 Paxos 相比,Raft 強調的是易理解、易實現,Raft 和 Paxos 一樣只要保證超過半數的節點正常就能夠提供服務。這篇文章 《ETCD 教程 - 2.Raft 協議》 詳細講解了 Raft 原理,非常有意思,感興趣的同學可以看看。

ZooKeeper Atomic Broadcast (ZAB, ZooKeeper 原子消息廣播協議) 是 ZooKeeper 實現分佈式數據一致性的核心算法,ZAB 借鑑 Paxos 算法,但又不像 Paxos 算法那樣,是一種通用的分佈式一致性算法,它是一種特別爲 ZooKeeper 專門設計的支持崩潰恢復的原子廣播協議。

常用註冊中心

這裏主要介紹 5 種常用的註冊中心,分別爲 Zookeeper、Eureka、Nacos、Consul 和 ETCD

Zookeeper

這個說起來有點意思的是官方並沒有說他是一個註冊中心,但是國內 Dubbo 場景下很多都是使用 Zookeeper 來完成了註冊中心的功能。

當然這有很多歷史原因,這裏我們就不追溯了。ZooKeeper 是非常經典的服務註冊中心中間件,在國內環境下,由於受到 Dubbo 框架的影響,大部分情況下認爲 Zookeeper 是 RPC 服務框架下注冊中心最好選擇,隨着 Dubbo 框架的不斷開發優化,和各種註冊中心組件的誕生,即使是 RPC 框架,現在的註冊中心也逐步放棄了 ZooKeeper。在常用的開發集羣環境中,ZooKeeper 依然起到十分重要的作用,Java 體系中,大部分的集羣環境都是依賴 ZooKeeper 管理服務的各個節點。

Zookeeper 如何實現註冊中心

具體可參考這篇文章 《Zookeeper 用作註冊中心的原理》,下面的內容都出自該文章。

Zookeeper 可以充當一個服務註冊表(Service Registry),讓多個服務提供者形成一個集羣,讓服務消費者通過服務註冊表獲取具體的服務訪問地址(Ip + 端口)去訪問具體的服務提供者。如下圖所示:

每當一個服務提供者部署後都要將自己的服務註冊到 zookeeper 的某一路徑上: /{service}/{version}/{ip:port} 。

比如我們的 HelloWorldService 部署到兩臺機器,那麼 Zookeeper 上就會創建兩條目錄:

這麼描述有點不好理解,下圖更直觀:

在 zookeeper 中,進行服務註冊,實際上就是在 zookeeper 中創建了一個 znode 節點,該節點存儲了該服務的 IP、端口、調用方式 (協議、序列化方式) 等。該節點承擔着最重要的職責,它由服務提供者 (發佈服務時) 創建,以供服務消費者獲取節點中的信息,從而定位到服務提供者真正網絡拓撲位置以及得知如何調用。

RPC 服務註冊 / 發現過程簡述如下:

  1. 服務提供者啓動時,會將其服務名稱,ip 地址註冊到配置中心。

  2. 服務消費者在第一次調用服務時,會通過註冊中心找到相應的服務的 IP 地址列表,並緩存到本地,以供後續使用。當消費者調用服務時,不會再去請求註冊中心,而是直接通過負載均衡算法從 IP 列表中取一個服務提供者的服務器調用服務。

  3. 當服務提供者的某臺服務器宕機或下線時,相應的 ip 會從服務提供者 IP 列表中移除。同時,註冊中心會將新的服務 IP 地址列表發送給服務消費者機器,緩存在消費者本機。

  4. 當某個服務的所有服務器都下線了,那麼這個服務也就下線了。

  5. 同樣,當服務提供者的某臺服務器上線時,註冊中心會將新的服務 IP 地址列表發送給服務消費者機器,緩存在消費者本機。

  6. 服務提供方可以根據服務消費者的數量來作爲服務下線的依據。

zookeeper 提供了 “心跳檢測” 功能:它會定時向各個服務提供者發送一個請求(實際上建立的是一個 socket 長連接),如果長期沒有響應,服務中心就認爲該服務提供者已經 “掛了”,並將其剔除。

比如 100.100.0.237 這臺機器如果宕機了,那麼 zookeeper 上的路徑就會只剩 / HelloWorldService/1.0.0/100.100.0.238:16888。

Zookeeper 的 Watch 機制其實就是一種推拉結合的模式

Zookeeper 不適合作爲註冊中心

作爲一個分佈式協同服務,ZooKeeper 非常好,但是對於 Service 發現服務來說就不合適了,因爲對於 Service 發現服務來說就算是返回了包含不實的信息的結果也比什麼都不返回要好。所以當向註冊中心查詢服務列表時,我們可以容忍註冊中心返回的是幾分鐘以前的註冊信息,但不能接受服務直接 down 掉不可用。

但是 zk 會出現這樣一種情況,當 master 節點因爲網絡故障與其他節點失去聯繫時,剩餘節點會重新進行 leader 選舉。問題在於,選舉 leader 的時間太長,30 ~ 120s, 且選舉期間整個 zk 集羣都是不可用的,這就導致在選舉期間註冊服務癱瘓。在雲部署的環境下,因網絡問題使得 zk 集羣失去 master 節點是較大概率會發生的事,雖然服務能夠最終恢復,但是漫長的選舉時間導致的註冊長期不可用是不能容忍的。

所以說,作爲註冊中心,可用性的要求要高於一致性!

在 CAP 模型中,Zookeeper 整體遵循一致性(CP)原則,即在任何時候對 Zookeeper 的訪問請求能得到一致的數據結果,但是當機器下線或者宕機時,不能保證服務可用性。

那爲什麼 Zookeeper 不使用最終一致性(AP)模型呢?因爲這個依賴 Zookeeper 的核心算法是 ZAB,所有設計都是爲了強一致性。這個對於分佈式協調系統,完全沒沒有毛病,但是你如果將 Zookeeper 爲分佈式協調服務所做的一致性保障,用在註冊中心,或者說服務發現場景,這個其實就不合適。

Eureka

Eureka 架構圖

什麼,上面這幅圖看起來很複雜?那我給你貼個簡化版:

Eureka 特點

除了上述特點,Eureka 還有一種自我保護機制,如果在 15 分鐘內超過 85% 的節點都沒有正常的心跳,那麼 Eureka 就認爲客戶端與註冊中心出現了網絡故障,此時會出現以下幾種情況:

Eureka 工作流程

瞭解完 Eureka 核心概念,自我保護機制,以及集羣內的工作原理後,我們來整體梳理一下 Eureka 的工作流程:

  1. Eureka Server 啓動成功,等待服務端註冊。在啓動過程中如果配置了集羣,集羣之間定時通過 Replicate 同步註冊表,每個 Eureka Server 都存在獨立完整的服務註冊表信息。

  2. Eureka Client 啓動時根據配置的 Eureka Server 地址去註冊中心註冊服務。

  3. Eureka Client 會每 30s 向 Eureka Server 發送一次心跳請求,證明客戶端服務正常。

  4. 當 Eureka Server 90s 內沒有收到 Eureka Client 的心跳,註冊中心則認爲該節點失效,會註銷該實例。

  5. 單位時間內 Eureka Server 統計到有大量的 Eureka Client 沒有上送心跳,則認爲可能爲網絡異常,進入自我保護機制,不再剔除沒有上送心跳的客戶端。

  6. 當 Eureka Client 心跳請求恢復正常之後,Eureka Server 自動退出自我保護模式。

  7. Eureka Client 定時全量或者增量從註冊中心獲取服務註冊表,並且將獲取到的信息緩存到本地。

  8. 服務調用時,Eureka Client 會先從本地緩存找尋調取的服務。如果獲取不到,先從註冊中心刷新註冊表,再同步到本地緩存。

  9. Eureka Client 獲取到目標服務器信息,發起服務調用。

  10. Eureka Client 程序關閉時向 Eureka Server 發送取消請求,Eureka Server 將實例從註冊表中刪除。

通過分析 Eureka 工作原理,我可以明顯地感覺到 Eureka 的設計之巧妙,完美地解決了註冊中心的穩定性和高可用性。

Eureka 爲了保障註冊中心的高可用性,容忍了數據的非強一致性,服務節點間的數據可能不一致, Client-Server 間的數據可能不一致。比較適合跨越多機房、對註冊中心服務可用性要求較高的使用場景。

Nacos

以下內容摘抄自 Nacos 官網:https://nacos.io/zh-cn/docs/what-is-nacos.html

Nacos 致力於幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集,幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理。

Nacos 幫助您更敏捷和容易地構建、交付和管理微服務平臺。Nacos 是構建以 “服務” 爲中心的現代應用架構 (例如微服務範式、雲原生範式) 的服務基礎設施。

Nacos 主要特點

服務發現和服務健康監測

動態配置服務

動態 DNS 服務

小節一下:

  • Nacos 是阿里開源的,支持基於 DNS 和基於 RPC 的服務發現。

  • Nacos 的註冊中心支持 CP 也支持 AP,對他來說只是一個命令的切換,隨你玩,還支持各種註冊中心遷移到 Nacos,反正一句話,只要你想要的他就有。

  • Nacos 除了服務的註冊發現之外,還支持動態配置服務,一句話概括就是 Nacos = Spring Cloud 註冊中心 + Spring Cloud 配置中心

Consul

Consul 是 HashiCorp 公司推出的開源工具,用於實現分佈式系統的服務發現與配置。與其它分佈式服務註冊與發現的方案,Consul 的方案更 “一站式”,內置了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value 存儲、多數據中心方案,不再需要依賴其它工具(比如 ZooKeeper 等)。

Consul 使用起來也較爲簡單,使用 Go 語言編寫,因此具有天然可移植性 (支持 Linux、windows 和 Mac OS X);安裝包僅包含一個可執行文件,方便部署,與 Docker 等輕量級容器可無縫配合。

Consul 的調用過程

  1. 當 Producer 啓動的時候,會向 Consul 發送一個 post 請求,告訴 Consul 自己的 IP 和 Port;

  2. Consul 接收到 Producer 的註冊後,每隔 10s(默認)會向 Producer 發送一個健康檢查的請求,檢驗 Producer 是否健康;

  3. 當 Consumer 發送 GET 方式請求 /api/address 到 Producer 時,會先從 Consul 中拿到一個存儲服務 IP 和 Port 的臨時表,從表中拿到 Producer 的 IP 和 Port 後再發送 GET 方式請求 /api/address;

  4. 該臨時表每隔 10s 會更新,只包含有通過了健康檢查的 Producer。

Consul 主要特徵

多數據中心

這裏純屬瞭解,學習一下 Consul 的多數據中心是如何實現的。

Consul 支持開箱即用的多數據中心,這意味着用戶不需要擔心需要建立額外的抽象層讓業務擴展到多個區域。

在上圖中有兩個 DataCenter,他們通過 Internet 互聯,同時請注意爲了提高通信效率,只有 Server 節點才加入跨數據中心的通信。

在單個數據中心中,Consul 分爲 Client 和 Server 兩種節點(所有的節點也被稱爲 Agent),Server 節點保存數據,Client 負責健康檢查及轉發數據請求到 Server;Server 節點有一個 Leader 和多個 Follower,Leader 節點會將數據同步到 Follower,Server 的數量推薦是 3 個或者 5 個,在 Leader 掛掉的時候會啓動選舉機制產生一個新的 Leader。

集羣內的 Consul 節點通過 gossip 協議(流言協議)維護成員關係,也就是說某個節點了解集羣內現在還有哪些節點,這些節點是 Client 還是 Server。單個數據中心的流言協議同時使用 TCP 和 UDP 通信,並且都使用 8301 端口。跨數據中心的流言協議也同時使用 TCP 和 UDP 通信,端口使用 8302。

集羣內數據的讀寫請求既可以直接發到 Server,也可以通過 Client 使用 RPC 轉發到 Server,請求最終會到達 Leader 節點,在允許數據延時的情況下,讀請求也可以在普通的 Server 節點完成,集羣內數據的讀寫和複製都是通過 TCP 的 8300 端口完成。

ETCD

etcd 是一個 Go 言編寫的分佈式、高可用的一致性鍵值存儲系統,用於提供可靠的分佈式鍵值存儲、配置共享和服務發現等功能。

ETCD 特點

ETCD 框架

etcd 主要分爲四個部分:

通常,一個用戶的請求發送過來,會經由 HTTP Server 轉發給 Store 進行具體的事務處理,如果涉及到節點的修改,則交給 Raft 模塊進行狀態的變更、日誌的記錄,然後再同步給別的 etcd 節點以確認數據提交,最後進行數據的提交,再次同步。

註冊中心對比 & 選型

註冊中心對比

註冊中心選型

關於註冊中心的對比和選型,其實上面已經講的非常清楚了,我給出一些個人理解:


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/st-y-SQxwKdG-iLyA8ph6g