五種注冊中心,如何選型?
大家好呀,我是樓仔。
最近發現很多號主發注冊中心的文章,質量參差不齊,相關文章我之前也寫過,建議直接看這篇。
這篇文章,主要講述 Zookeeper、Eureka、Nacos、Consul 和 Etcd 這 5 種注冊中心,無論是面試,還是用于技術選型,都有非常強的參考價值。
全文接近 8千字,有點長,建議先收藏,再慢慢看,下面是文章目錄:
圖片
01 注冊中心基本概念
1.1 什么是注冊中心?
注冊中心主要有三種角色:
- 服務提供者(RPC Server):在啟動時,向 Registry 注冊自身服務,并向 Registry 定期發送心跳匯報存活狀態。
- 服務消費者(RPC Client):在啟動時,向 Registry 訂閱服務,把 Registry 返回的服務節點列表緩存在本地內存中,并與 RPC Sever 建立連接。
- 服務注冊中心(Registry):用于保存 RPC Server 的注冊信息,當 RPC Server 節點發生變更時,Registry 會同步變更,RPC Client 感知后會刷新本地 內存中緩存的服務節點列表。
最后,RPC Client 從本地緩存的服務節點列表中,基于負載均衡算法選擇一臺 RPC Sever 發起調用。
圖片
1.2 注冊中心需要實現功能
根據注冊中心原理的描述,注冊中心必須實現以下功能,偷個懶,直接貼幅圖:
圖片
02 注冊中心基礎掃盲
2.1 CAP理論
CAP理論是分布式架構中重要理論:
- 一致性(Consistency):所有節點在同一時間具有相同的數據;
- 可用性(Availability) :保證每個請求不管成功或者失敗都有響應;
- 分隔容忍(Partition tolerance) :系統中任意信息的丟失或失敗不會影響系統的繼續運作。
關于 P 的理解,我覺得是在整個系統中某個部分,掛掉了,或者宕機了,并不影響整個系統的運作或者說使用,而可用性是,某個系統的某個節點掛了,但是并不影響系統的接受或者發出請求。
CAP 不可能都取,只能取其中2個的原因如下:
- 如果C是第一需求的話,那么會影響A的性能,因為要數據同步,不然請求結果會有差異,但是數據同步會消耗時間,期間可用性就會降低。
- 如果A是第一需求,那么只要有一個服務在,就能正常接受請求,但是對于返回結果變不能保證,原因是,在分布式部署的時候,數據一致的過程不可能想切線路那么快。
- 再如果,同時滿足一致性和可用性,那么分區容錯就很難保證了,也就是單點,也是分布式的基本核心。
2.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一樣只要保證超過半數的節點正常就能夠提供服務。
ZooKeeper Atomic Broadcast (ZAB, ZooKeeper原子消息廣播協議)是ZooKeeper實現分布式數據一致性的核心算法,ZAB借鑒Paxos算法,但又不像Paxos算法那樣,是一種通用的分布式一致性算法,它是一種特別為ZooKeeper專門設計的支持崩潰恢復的原子廣播協議。
03 常用注冊中心
這里主要介紹5種常用的注冊中心,分別為Zookeeper、Eureka、Nacos、Consul和ETCD。
3.1 Zookeeper
這個說起來有點意思的是官方并沒有說他是一個注冊中心,但是國內Dubbo場景下很多都是使用Zookeeper來完成了注冊中心的功能。
當然這有很多歷史原因,這里我們就不追溯了。ZooKeeper是非常經典的服務注冊中心中間件,在國內環境下,由于受到Dubbo框架的影響,大部分情況下認為Zookeeper是RPC服務框架下注冊中心最好選擇,隨著Dubbo框架的不斷開發優化,和各種注冊中心組件的誕生,即使是RPC框架,現在的注冊中心也逐步放棄了ZooKeeper。在常用的開發集群環境中,ZooKeeper依然起到十分重要的作用,Java體系中,大部分的集群環境都是依賴ZooKeeper管理服務的各個節點。
圖片
Zookeeper如何實現注冊中心
Zookeeper可以充當一個服務注冊表(Service Registry),讓多個服務提供者形成一個集群,讓服務消費者通過服務注冊表獲取具體的服務訪問地址(Ip+端口)去訪問具體的服務提供者。如下圖所示:
圖片
每當一個服務提供者部署后都要將自己的服務注冊到zookeeper的某一路徑上: /{service}/{version}/{ip:port} 。
比如我們的HelloWorldService部署到兩臺機器,那么Zookeeper上就會創建兩條目錄:
- /HelloWorldService/1.0.0/100.19.20.01:16888
- /HelloWorldService/1.0.0/100.19.20.02:16888
這么描述有點不好理解,下圖更直觀:
圖片
在zookeeper中,進行服務注冊,實際上就是在zookeeper中創建了一個znode節點,該節點存儲了該服務的IP、端口、調用方式(協議、序列化方式)等。該節點承擔著最重要的職責,它由服務提供者(發布服務時)創建,以供服務消費者獲取節點中的信息,從而定位到服務提供者真正網絡拓撲位置以及得知如何調用。
RPC服務注冊/發現過程簡述如下:
- 服務提供者啟動時,會將其服務名稱,ip地址注冊到配置中心。
- 服務消費者在第一次調用服務時,會通過注冊中心找到相應的服務的IP地址列表,并緩存到本地,以供后續使用。當消費者調用服務時,不會再去請求注冊中心,而是直接通過負載均衡算法從IP列表中取一個服務提供者的服務器調用服務。
- 當服務提供者的某臺服務器宕機或下線時,相應的ip會從服務提供者IP列表中移除。同時,注冊中心會將新的服務IP地址列表發送給服務消費者機器,緩存在消費者本機。
- 當某個服務的所有服務器都下線了,那么這個服務也就下線了。
- 同樣,當服務提供者的某臺服務器上線時,注冊中心會將新的服務IP地址列表發送給服務消費者機器,緩存在消費者本機。
- 服務提供方可以根據服務消費者的數量來作為服務下線的依據。
zookeeper提供了“心跳檢測”功能:它會定時向各個服務提供者發送一個請求(實際上建立的是一個 socket 長連接),如果長期沒有響應,服務中心就認為該服務提供者已經“掛了”,并將其剔除。
比如100.100.0.237這臺機器如果宕機了,那么zookeeper上的路徑就會只剩/HelloWorldService/1.0.0/100.100.0.238:16888。
Zookeeper的Watch機制其實就是一種推拉結合的模式:
- 服務消費者會去監聽相應路徑(/HelloWorldService/1.0.0),一旦路徑上的數據有任務變化(增加或減少),Zookeeper只會發送一個事件類型和節點信息給關注的客戶端,而不會包括具體的變更內容,所以事件本身是輕量級的,這就是推的部分。
- 收到變更通知的客戶端需要自己去拉變更的數據,這就是拉的部分。
Zookeeper不適合作為注冊中心
作為一個分布式協同服務,ZooKeeper非常好,但是對于Service發現服務來說就不合適了,因為對于Service發現服務來說就算是返回了包含不實的信息的結果也比什么都不返回要好。所以當向注冊中心查詢服務列表時,我們可以容忍注冊中心返回的是幾分鐘以前的注冊信息,但不能接受服務直接down掉不可用。
但是zk會出現這樣一種情況,當master節點因為網絡故障與其他節點失去聯系時,剩余節點會重新進行leader選舉。問題在于,選舉leader的時間太長,30 ~ 120s, 且選舉期間整個zk集群都是不可用的,這就導致在選舉期間注冊服務癱瘓。在云部署的環境下,因網絡問題使得zk集群失去master節點是較大概率會發生的事,雖然服務能夠最終恢復,但是漫長的選舉時間導致的注冊長期不可用是不能容忍的。
所以說,作為注冊中心,可用性的要求要高于一致性!
在 CAP 模型中,Zookeeper整體遵循一致性(CP)原則,即在任何時候對 Zookeeper 的訪問請求能得到一致的數據結果,但是當機器下線或者宕機時,不能保證服務可用性。
那為什么Zookeeper不使用最終一致性(AP)模型呢?因為這個依賴Zookeeper的核心算法是ZAB,所有設計都是為了強一致性。這個對于分布式協調系統,完全沒沒有毛病,但是你如果將Zookeeper為分布式協調服務所做的一致性保障,用在注冊中心,或者說服務發現場景,這個其實就不合適。
3.2 Eureka
Eureka 架構圖
圖片
什么,上面這幅圖看起來很復雜?那我給你貼個簡化版:
圖片
Eureka 特點
- 可用性(AP原則):Eureka 在設計時就緊遵AP原則,Eureka的集群中,只要有一臺Eureka還在,就能保證注冊服務可用,只不過查到的信息可能不是最新的(不保證強一致性)。
- 去中心化架構:Eureka Server 可以運行多個實例來構建集群,不同于 ZooKeeper 的選舉 leader 的過程,Eureka Server 采用的是Peer to Peer 對等通信。這是一種去中心化的架構,無 master/slave 之分,每一個 Peer 都是對等的。節點通過彼此互相注冊來提高可用性,每個節點需要添加一個或多個有效的 serviceUrl 指向其他節點。每個節點都可被視為其他節點的副本。
- 請求自動切換:在集群環境中如果某臺 Eureka Server 宕機,Eureka Client 的請求會自動切換到新的 Eureka Server 節點上,當宕機的服務器重新恢復后,Eureka 會再次將其納入到服務器集群管理之中。
- 節點間操作復制:當節點開始接受客戶端請求時,所有的操作都會在節點間進行復制操作,將請求復制到該 Eureka Server 當前所知的其它所有節點中。
- 自動注冊&心跳:當一個新的 Eureka Server 節點啟動后,會首先嘗試從鄰近節點獲取所有注冊列表信息,并完成初始化。Eureka Server 通過 getEurekaServiceUrls() 方法獲取所有的節點,并且會通過心跳契約的方式定期更新。
- 自動下線:默認情況下,如果 Eureka Server 在一定時間內沒有接收到某個服務實例的心跳(默認周期為30秒),Eureka Server 將會注銷該實例(默認為90秒, eureka.instance.lease-expiration-duration-in-seconds 進行自定義配置)。
- 保護模式:當 Eureka Server 節點在短時間內丟失過多的心跳時,那么這個節點就會進入自我保護模式。
除了上述特點,Eureka還有一種自我保護機制,如果在15分鐘內超過 85% 的節點都沒有正常的心跳,那么Eureka就認為客戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:
- Eureka不再從注冊表中移除因為長時間沒有收到心跳而過期的服務;
- Eureka仍然能夠接受新服務注冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用)
- 當網絡穩定時,當前實例新注冊的信息會被同步到其它節點中。
Eureka工作流程
了解完 Eureka 核心概念,自我保護機制,以及集群內的工作原理后,我們來整體梳理一下 Eureka 的工作流程:
- Eureka Server 啟動成功,等待服務端注冊。在啟動過程中如果配置了集群,集群之間定時通過 Replicate 同步注冊表,每個 Eureka Server 都存在獨立完整的服務注冊表信息。
- Eureka Client 啟動時根據配置的 Eureka Server 地址去注冊中心注冊服務。
- Eureka Client 會每 30s 向 Eureka Server 發送一次心跳請求,證明客戶端服務正常。
- 當 Eureka Server 90s 內沒有收到 Eureka Client 的心跳,注冊中心則認為該節點失效,會注銷該實例。
- 單位時間內 Eureka Server 統計到有大量的 Eureka Client 沒有上送心跳,則認為可能為網絡異常,進入自我保護機制,不再剔除沒有上送心跳的客戶端。
- 當 Eureka Client 心跳請求恢復正常之后,Eureka Server 自動退出自我保護模式。
- Eureka Client 定時全量或者增量從注冊中心獲取服務注冊表,并且將獲取到的信息緩存到本地。
- 服務調用時,Eureka Client 會先從本地緩存找尋調取的服務。如果獲取不到,先從注冊中心刷新注冊表,再同步到本地緩存。
- Eureka Client 獲取到目標服務器信息,發起服務調用。
- Eureka Client 程序關閉時向 Eureka Server 發送取消請求,Eureka Server 將實例從注冊表中刪除。
通過分析 Eureka 工作原理,我可以明顯地感覺到 Eureka 的設計之巧妙,完美地解決了注冊中心的穩定性和高可用性。
Eureka 為了保障注冊中心的高可用性,容忍了數據的非強一致性,服務節點間的數據可能不一致, Client-Server 間的數據可能不一致。比較適合跨越多機房、對注冊中心服務可用性要求較高的使用場景。
3.3 Nacos
以下內容摘抄自Nacos官網:https://nacos.io/zh-cn/docs/what-is-nacos.html
圖片
Nacos 致力于幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集,幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理。
Nacos 幫助您更敏捷和容易地構建、交付和管理微服務平臺。Nacos 是構建以“服務”為中心的現代應用架構 (例如微服務范式、云原生范式) 的服務基礎設施。
圖片
Nacos 主要特點
服務發現和服務健康監測:
- Nacos 支持基于 DNS 和基于 RPC 的服務發現。服務提供者使用原生SDK、OpenAPI、或一個獨立的Agent TODO注冊 Service 后,服務消費者可以使用DNS TODO 或HTTP&API查找和發現服務。
- Nacos 提供對服務的實時的健康檢查,阻止向不健康的主機或服務實例發送請求。Nacos 支持傳輸層 (PING 或 TCP)和應用層 (如 HTTP、MySQL、用戶自定義)的健康檢查。對于復雜的云環境和網絡拓撲環境中(如 VPC、邊緣網絡等)服務的健康檢查,Nacos 提供了 agent 上報模式和服務端主動檢測2種健康檢查模式。Nacos 還提供了統一的健康檢查儀表盤,幫助您根據健康狀態管理服務的可用性及流量。
動態配置服務:
- 動態配置服務可以讓您以中心化、外部化和動態化的方式管理所有環境的應用配置和服務配置。
- 動態配置消除了配置變更時重新部署應用和服務的需要,讓配置管理變得更加高效和敏捷。
- 配置中心化管理讓實現無狀態服務變得更簡單,讓服務按需彈性擴展變得更容易。
- Nacos 提供了一個簡潔易用的UI (控制臺樣例 Demo) 幫助您管理所有的服務和應用的配置。Nacos 還提供包括配置版本跟蹤、金絲雀發布、一鍵回滾配置以及客戶端配置更新狀態跟蹤在內的一系列開箱即用的配置管理特性,幫助您更安全地在生產環境中管理配置變更和降低配置變更帶來的風險。
動態 DNS 服務:
- 動態 DNS 服務支持權重路由,讓您更容易地實現中間層負載均衡、更靈活的路由策略、流量控制以及數據中心內網的簡單DNS解析服務。動態DNS服務還能讓您更容易地實現以 DNS 協議為基礎的服務發現,以幫助您消除耦合到廠商私有服務發現 API 上的風險。
- Nacos 提供了一些簡單的 DNS APIs TODO 幫助您管理服務的關聯域名和可用的 IP:PORT 列表。
小節一下:
- Nacos是阿里開源的,支持基于 DNS 和基于 RPC 的服務發現。
- Nacos的注冊中心支持CP也支持AP,對他來說只是一個命令的切換,隨你玩,還支持各種注冊中心遷移到Nacos,反正一句話,只要你想要的他就有。
- Nacos除了服務的注冊發現之外,還支持動態配置服務,一句話概括就是Nacos = Spring Cloud注冊中心 + Spring Cloud配置中心。
3.4 Consul
Consul 是 HashiCorp 公司推出的開源工具,用于實現分布式系統的服務發現與配置。與其它分布式服務注冊與發現的方案,Consul 的方案更“一站式”,內置了服務注冊與發現框 架、分布一致性協議實現、健康檢查、Key/Value 存儲、多數據中心方案,不再需要依賴其它工具(比如 ZooKeeper 等)。
Consul 使用起來也較為簡單,使用 Go 語言編寫,因此具有天然可移植性(支持Linux、windows和Mac OS X);安裝包僅包含一個可執行文件,方便部署,與 Docker 等輕量級容器可無縫配合。
Consul 的調用過程
- 當 Producer 啟動的時候,會向 Consul 發送一個 post 請求,告訴 Consul 自己的 IP 和 Port;
- Consul 接收到 Producer 的注冊后,每隔 10s(默認)會向 Producer 發送一個健康檢查的請求,檢驗 Producer 是否健康;
- 當 Consumer 發送 GET 方式請求 /api/address 到 Producer 時,會先從 Consul 中拿到一個存儲服務 IP 和 Port 的臨時表,從表中拿到 Producer 的 IP 和 Port 后再發送 GET 方式請求 /api/address;
- 該臨時表每隔 10s 會更新,只包含有通過了健康檢查的 Producer。
圖片
Consul 主要特征
- CP模型,使用 Raft 算法來保證強一致性,不保證可用性;
- 支持服務注冊與發現、健康檢查、KV Store功能。
- 支持多數據中心,可以避免單數據中心的單點故障,而其部署則需要考慮網絡延遲, 分片等情況等。
- 支持安全服務通信,Consul可以為服務生成和分發TLS證書,以建立相互的TLS連接。
- 支持 http 和 dns 協議接口;
- 官方提供 web 管理界面。
多數據中心
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端口完成。
3.5 ETCD
etcd是一個Go言編寫的分布式、高可用的一致性鍵值存儲系統,用于提供可靠的分布式鍵值存儲、配置共享和服務發現等功能。
ETCD 特點
- 易使用:基于HTTP+JSON的API讓你用curl就可以輕松使用;
- 易部署:使用Go語言編寫,跨平臺,部署和維護簡單;
- 強一致:使用Raft算法充分保證了分布式系統數據的強一致性;
- 高可用:具有容錯能力,假設集群有n個節點,當有(n-1)/2節點發送故障,依然能提供服務;
- 持久化:數據更新后,會通過WAL格式數據持久化到磁盤,支持Snapshot快照;
- 快速:每個實例每秒支持一千次寫操作,極限寫性能可達10K QPS;
- 安全:可選SSL客戶認證機制;
- ETCD 3.0:除了上述功能,還支持gRPC通信、watch機制。
ETCD 框架
etcd主要分為四個部分:
- HTTP Server:用于處理用戶發送的API請求以及其它etcd節點的同步與心跳信息請求。
- Store:用于處理etcd支持的各類功能的事務,包括數據索引、節點狀態變更、監控與反饋、事件處理與執行等等,是etcd對用戶提供的大多數API功能的具體實現。
- Raft:Raft強一致性算法的具體實現,是etcd的核心。
- WAL:Write Ahead Log(預寫式日志),是etcd的數據存儲方式。除了在內存中存有所有數據的狀態以及節點的索引以外,etcd就通過WAL進行持久化存儲。WAL中,所有的數據提交前都會事先記錄日志。Snapshot是為了防止數據過多而進行的狀態快照;Entry表示存儲的具體日志內容。
圖片
通常,一個用戶的請求發送過來,會經由HTTP Server轉發給Store進行具體的事務處理,如果涉及到節點的修改,則交給Raft模塊進行狀態的變更、日志的記錄,然后再同步給別的etcd節點以確認數據提交,最后進行數據的提交,再次同步。
04 注冊中心對比&選型
4.1 注冊中心對比
圖片
圖片
- 服務健康檢查:Euraka 使用時需要顯式配置健康檢查支持;Zookeeper、Etcd 則在失去了和服務進程的連接情況下任務不健康,而 Consul 相對更為詳細點,比如內存是否已使用了90%,文件系統的空間是不是快不足了。
- 多數據中心:Consul 和 Nacos 都支持,其他的產品則需要額外的開發工作來實現。
- KV 存儲服務:除了 Eureka,其他幾款都能夠對外支持 k-v 的存儲服務,所以后面會講到這幾款產品追求高一致性的重要原因。而提供存儲服務,也能夠較好的轉化為動態配置服務哦。
- CAP 理論的取舍:
- Eureka 是典型的 AP,Nacos可以配置為 AP,作為分布式場景下的服務發現的產品較為合適,服務發現場景的可用性優先級較高,一致性并不是特別致命。
- 而Zookeeper、Etcd、Consul則是 CP 類型犧牲可用性,在服務發現場景并沒太大優勢;
- Watch的支持:Zookeeper 支持服務器端推送變化,其它都通過長輪詢的方式來實現變化的感知。
- 自身集群的監控:除了Zookeeper和Nacos,其它幾款都默認支持 metrics,運維者可以搜集并報警這些度量信息達到監控目的。
- Spring Cloud的集成:目前都有相對應的 boot starter,提供了集成能力。
4.2 注冊中心選型
關于注冊中心的對比和選型,其實上面已經講的非常清楚了,我給出一些個人理解:
- 關于CP還是AP的選擇:選擇 AP,因為可用性高于一致性,所以更傾向 Eureka 和 Nacos;關于Eureka、Nacos如何選擇,哪個讓我做的事少,我就選擇哪個,顯然 Nacos 幫我們做了更多的事。
- 技術體系:Etcd 和 Consul 都是Go開發的,Eureka、Nacos、Zookeeper 和 Zookeeper 都是Java開發的,可能項目屬于不同的技術棧,會偏向選擇對應的技術體系。
- 高可用:這幾款開源產品都已經考慮如何搭建高可用集群,有些差別而已;
- 產品的活躍度:這幾款開源產品整體上都比較活躍。