文章目錄
- ZooKeeper、Eureka、Consul 、Nacos,微服務注冊中心怎麼選?
-
- 前言
- CAP理論
- 服務注冊中心解決方案
- 主流注冊中心産品
- Apache Zookeeper → CP
- Spring Cloud Eureka → AP
- Consul → CP
-
- Consul Template
- Nacos
ZooKeeper、Eureka、Consul 、Nacos,微服務注冊中心怎麼選?
前言
服務注冊中心本質上是為了解耦服務提供者和服務消費者。對于任何一個微服務,原則上都應存在或者支援多個提供者,這是由微服務的分布式屬性決定的。更進一步,為了支援彈性擴縮容特性,一個微服務的提供者的數量和分布往往是動态變化的,也是無法預先确定的。是以,原本在單體應用階段常用的靜态 LB 機制就不再适用了,需要引入額外的元件來管理微服務提供者的注冊與發現,而這個元件就是服務注冊中心。
CAP理論
CAP 理論是分布式架構中重要理論
- 一緻性 (Consistency) 所有節點在同一時間具有相同的資料
- 可用性 (Availability) 保證每個請求不管成功或者失敗都有響應
- 分隔容忍 (Partition tolerance) 系統中任意資訊的丢失或失敗不會影響系統的繼續運作
關于 P 的了解,我覺得是在整個系統中某個部分,挂掉了,或者當機了,并不影響整個系統的運作或者說使用,而可用性是,某個系統的某個節點挂了,但是并不影響系統的接受或者送出請求,CAP 不可能都滿足,隻能取其中 2 個原因是如果 C 是第一需求的話,那麼會影響 A 的性能,因為要資料同步,不然請求結果會有差異,但是資料同步會消耗時間,期間可用性就會降低。
如果 A 是第一需求,那麼隻要有一個服務在,就能正常接受請求,但是對與傳回結果就不能保證資料一緻性,原因是,在分布式部署的時候,資料一緻的過程不可能想切線路那麼快。
再如果,同時滿足一緻性和可用性,那麼分區容錯就很難保證了,也就是單點,也是分布式的基本核心,好了,明白這些理論,就可以在相應的場景選取服務注冊與發現了
服務注冊中心解決方案
設計或者選型一個服務注冊中心,首先要考慮的就是服務注冊與發現機制。縱觀當下各種主流的服務注冊中心解決方案,大緻可歸為三類:
- 應用内:直接內建到應用中,依賴于應用自身完成服務的注冊與發現,最典型的是 Netflix 提供的 Eureka
- 應用外:把應用當成黑盒,通過應用外的某種機制将服務注冊到注冊中心,最小化對應用的侵入性,比如 Airbnb 的 SmartStack,HashiCorp 的 Consul
- DNS:将服務注冊為 DNS 的 SRV 記錄,嚴格來說,是一種特殊的應用外注冊方式,SkyDNS 是其中的代表
注 1: 對于第一類注冊方式,除了 Eureka 這種一站式解決方案,還可以基于 ZooKeeper 或者 Etcd 自行實作一套服務注冊機制,這在大公司比較常見,但對于小公司而言顯然成本效益太低。
注 2: 由于 DNS 固有的緩存缺陷,本文不對第三類注冊方式作深入探讨。
除了基本的服務注冊與發現機制,從開發和運維角度,至少還要考慮如下五個方面:
- 測活:服務注冊之後,如何對服務進行測活以保證服務的可用性?
- 負載均衡:當存在多個服務提供者時,如何均衡各個提供者的負載?
- 內建:在服務提供端或者調用端,如何內建注冊中心?
- 運作時依賴:引入注冊中心之後,對應用的運作時環境有何影響?
- 可用性:如何保證注冊中心本身的可用性,特别是消除單點故障?
主流注冊中心産品
軟體産品特性并非一成不變,如果發現功能特性有變更,歡迎評論指正
Apache Zookeeper → CP
與 Eureka 有所不同,Apache Zookeeper 在設計時就緊遵 CP 原則,即任何時候對 Zookeeper 的通路請求能得到一緻的資料結果,同時系統對網絡分割具備容錯性,但是 Zookeeper 不能保證每次服務請求都是可達的。
從 Zookeeper 的實際應用情況來看,在使用 Zookeeper 擷取服務清單時,如果此時的 Zookeeper 叢集中的 Leader 當機了,該叢集就要進行 Leader 的選舉,又或者 Zookeeper 叢集中半數以上伺服器節點不可用(例如有三個節點,如果節點一檢測到節點三挂了 ,節點二也檢測到節點三挂了,那這個節點才算是真的挂了),那麼将無法處理該請求。是以說,Zookeeper 不能保證服務可用性。
當然,在大多數分布式環境中,尤其是涉及到資料存儲的場景,資料一緻性應該是首先被保證的,這也是 Zookeeper 設計緊遵 CP 原則的另一個原因。
但是對于服務發現來說,情況就不太一樣了,針對同一個服務,即使注冊中心的不同節點儲存的服務提供者資訊不盡相同,也并不會造成災難性的後果。
因為對于服務消費者來說,能消費才是最重要的,消費者雖然拿到可能不正确的服務執行個體資訊後嘗試消費一下,也要勝過因為無法擷取執行個體資訊而不去消費,導緻系統異常要好(淘寶的雙十一,京東的 618 就是緊遵 AP 的最好參照)。
當 master 節點因為網絡故障與其他節點失去聯系時,剩餘節點會重新進行 leader 選舉。問題在于,選舉 leader 的時間太長,30~120s,而且選舉期間整個 zk 叢集都是不可用的,這就導緻在選舉期間注冊服務癱瘓。
在雲部署環境下, 因為網絡問題使得 zk 叢集失去 master 節點是大機率事件,雖然服務能最終恢複,但是漫長的選舉事件導緻注冊長期不可用是不能容忍的。
Spring Cloud Eureka → AP
Spring Cloud Netflix 在設計 Eureka 時就緊遵 AP 原則(盡管現在 2.0 釋出了,但是由于其閉源的原因 ,目前 Ereka 1.x 任然是比較活躍的)。
Eureka Server 也可以運作多個執行個體來建構叢集,解決單點問題,但不同于 ZooKeeper 的選舉 leader 的過程,Eureka Server 采用的是 Peer to Peer 對等通信。這是一種去中心化的架構,無 master/slave 之分,每一個 Peer 都是對等的。在這種架構風格中,節點通過彼此互相注冊來提高可用性,每個節點需要添加一個或多個有效的 serviceUrl 指向其他節點。每個節點都可被視為其他節點的副本。
在叢集環境中如果某台 Eureka Server 當機,Eureka Client 的請求會自動切換到新的 Eureka Server 節點上,當當機的伺服器重新恢複後,Eureka 會再次将其納入到伺服器叢集管理之中。當節點開始接受用戶端請求時,所有的操作都會在節點間進行複制(replicate To Peer)操作,将請求複制到該 Eureka Server 目前所知的其它所有節點中。
當一個新的 Eureka Server 節點啟動後,會首先嘗試從鄰近節點擷取所有注冊清單資訊,并完成初始化。Eureka Server 通過 getEurekaServiceUrls() 方法擷取所有的節點,并且會通過心跳契約的方式定期更新。
預設情況下,如果 Eureka Server 在一定時間内沒有接收到某個服務執行個體的心跳(預設周期為 30 秒),Eureka Server 将會登出該執行個體(預設為 90 秒, eureka.instance.lease-expiration-duration-in-seconds 進行自定義配置)。
當 Eureka Server 節點在短時間内丢失過多的心跳時,那麼這個節點就會進入自我保護模式。
Eureka 的叢集中,隻要有一台 Eureka 還在,就能保證注冊服務可用(保證可用性),隻不過查到的資訊可能不是最新的(不保證強一緻性)。除此之外,Eureka 還有一種自我保護機制,如果在 15 分鐘内超過 85% 的節點都沒有正常的心跳,那麼 Eureka 就認為用戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:
- Eureka 不再從系統資料庫中移除因為長時間沒有收到心跳而過期的服務;
- Eureka 仍然能夠接受新服務注冊和查詢請求,但是不會被同步到其它節點上(即保證目前節點依然可用);
- 當網絡穩定時,目前執行個體新注冊的資訊會被同步到其它節點中;
是以,Eureka 可以很好的應對因網絡故障導緻部分節點失去聯系的情況,而不會像 zookeeper 那樣使得整個注冊服務癱瘓。
Consul → CP
Consul 是 HashiCorp 公司推出的開源工具,用于實作分布式系統的服務發現與配置。Consul 使用 Go 語言編寫,是以具有天然可移植性(支援 Linux、windows 和 Mac OS X)。
Consul 内置了服務注冊與發現架構、分布一緻性協定實作、健康檢查、Key/Value 存儲、多資料中心方案,不再需要依賴其他工具(比如 ZooKeeper 等),使用起來也較為簡單。
Consul 遵循 CAP 原理中的 CP 原則,保證了強一緻性和分區容錯性,且使用的是 Raft 算法,比 zookeeper 使用的 Paxos 算法更加簡單。雖然保證了強一緻性,但是可用性就相應下降了,例如服務注冊的時間會稍長一些,因為 Consul 的 raft 協定要求必須過半數的節點都寫入成功才認為注冊成功 ;在 leader 挂掉了之後,重新選舉出 leader 之前會導緻 Consul 服務不可用。
Consul 本質上屬于應用外的注冊方式,但可以通過 SDK 簡化注冊流程。而服務發現恰好相反,預設依賴于 SDK,但可以通過 Consul Template(下文會提到)去除 SDK 依賴。
Consul Template
Consul,預設服務調用者需要依賴 Consul SDK 來發現服務,這就無法保證對應用的零侵入性。
所幸通過 Consul Template,可以定時從 Consul 叢集擷取最新的服務提供者清單并重新整理 LB 配置(比如 nginx 的 upstream),這樣對于服務調用者而言,隻需要配置一個統一的服務調用位址即可。
Consul 強一緻性 © 帶來的是:
- 服務注冊相比 Eureka 會稍慢一些。因為 Consul 的 raft 協定要求必須過半數的節點都寫入成功才認為注冊成功
- Leader 挂掉時,重新選舉期間整個 consul 不可用。保證了強一緻性但犧牲了可用性。
Eureka 保證高可用 (A) 和最終一緻性:
- 服務注冊相對要快,因為不需要等注冊資訊 replicate(複制) 到其他節點,也不保證注冊資訊是否 replicate 成功
- 當資料出現不一緻時,雖然 A, B 上的注冊資訊不完全相同,但每個 Eureka 節點依然能夠正常對外提供服務,這會出現查詢服務資訊時如果請求 A 查不到,但請求 B 就能查到。如此保證了可用性但犧牲了一緻性。
其他方面,eureka 就是個 servlet 程式,跑在 servlet 容器中; Consul 則是 go 編寫而成。
Nacos
Nacos 是阿裡開源的,Nacos 支援基于 DNS 和基于 RPC 的服務發現。在 Spring Cloud 中使用 Nacos,隻需要先下載下傳 Nacos 并啟動 Nacos server,Nacos 隻需要簡單的配置就可以完成服務的注冊發現。
Nacos 除了服務的注冊發現之外,還支援動态配置服務。動态配置服務可以讓您以中心化、外部化和動态化的方式管理所有環境的應用配置和服務配置。動态配置消除了配置變更時重新部署應用和服務的需要,讓配置管理變得更加高效和靈活。配置中心化管理讓實作無狀态服務變得更簡單,讓服務按需彈性擴充變得更容易。
一句話概括就是 Nacos = Spring Cloud 注冊中心 + Spring Cloud 配置中心。
轉載:https://mp.weixin.qq.com/s/qUb3F42LO8dk2zja3prFyQ