1. 前言
服務注冊中心,給客戶端提供可供調用的服務列表,客戶端在進行遠程服務調用時,根據服務列表然后選擇服務提供方的服務地址進行服務調用。服務注冊中心在分布式系統中大量應用,是分布式系統中不可或缺的組件,例如rocketmq的name server,hdfs中的namenode,dubbo中的zk注冊中心,spring cloud中的服務注冊中心eureka。
在spring cloud中,除了可以使用eureka作為注冊中心外,還可以通過配置的方式使用zookeeper作為注冊中心。既然這樣,我們該如何選擇注冊中心的實現呢?
著名的CAP理論指出,一個分布式系統不可能同時滿足C(一致性)、A(可用性)和P(分區容錯性)。由於分區容錯性在是分布式系統中必須要保證的,因此我們只能在A和C之間進行權衡。在此Zookeeper保證的是CP, 而Eureka則是AP。
Consistency
中文叫做"一致性"。意思是,寫操作之后的讀操作,必須返回該值。舉例來說,某條記錄是 v0,用戶向 G1 發起一個寫操作,將其改為 v1,接下來,用戶的讀操作就會得到 v1。這就叫一致性。
Availability
中文叫做"可用性",意思是只要收到用戶的請求,服務器就必須給出回應。用戶可以選擇向 G1 或 G2 發起讀操作。不管是哪台服務器,只要收到請求,就必須告訴用戶,到底是 v0 還是 v1,否則就不滿足可用性。
Partition tolerance:
中文叫做"分區容錯",大多數分布式系統都分布在多個子網絡。每個子網絡就叫做一個區(partition)。分區容錯的意思是,區間通信可能失敗。比如,一台服務器放在中國,另一台服務器放在美國,這就是兩個區,它們之間可能無法通信。
即在一個分布式系統中,只能滿足其中的兩個,且在一般情況下,都是要滿足分區容錯性的。
2. Zookeeper保證CP
當向注冊中心查詢服務列表時,我們可以容忍注冊中心返回的是幾分鍾以前的注冊信息,但不能接受服務直接down掉不可用。也就是說,服務注冊功能對可用性的要求要高於一致性。但是zk會出現這樣一種情況,當master節點因為網絡故障與其他節點失去聯系時,剩余節點會重新進行leader選舉。問題在於,選舉leader的時間太長,30 ~ 120s, 且選舉期間整個zk集群都是不可用的,這就導致在選舉期間注冊服務癱瘓。在雲部署的環境下,因網絡問題使得zk集群失去master節點是較大概率會發生的事,雖然服務能夠最終恢復,但是漫長的選舉時間導致的注冊長期不可用是不能容忍的。
ZooKeeper 集群中的所有機器通過一個 Leader 選舉過程來選定一台稱為 “Leader” 的機器,Leader 既可以為客戶端提供寫服務又能提供讀服務。除了 Leader 外,Follower 和 Observer 都只能提供讀服務。Follower 和 Observer 唯一的區別在於 Observer 機器不參與 Leader 的選舉過程,也不參與寫操作的“過半寫成功”策略,因此 Observer 機器可以在不影響寫性能的情況下提升集群的讀性能。
當 Leader 服務器出現網絡中斷、崩潰退出與重啟等異常情況時,ZAB 協議就會進人恢復模式並選舉產生新的Leader服務器。這個過程大致是這樣的:
-
- Leader election(選舉階段):節點在一開始都處於選舉階段,只要有一個節點得到超半數節點的票數,它就可以當選准 leader。
- Discovery(發現階段):在這個階段,followers 跟准 leader 進行通信,同步 followers 最近接收的事務提議。
- Synchronization(同步階段):同步階段主要是利用 leader 前一階段獲得的最新提議歷史,同步集群中所有的副本。同步完成之后 准 leader 才會成為真正的 leader。
- Broadcast(廣播階段) 到了這個階段,Zookeeper 集群才能正式對外提供事務服務,並且 leader 可以進行消息廣播。同時如果有新的節點加入,還需要對新節點進行同步。
2.1ZooKeeper &ZAB 協議&Paxos算法
2.1.1 ZAB 協議&Paxos算法
Paxos 算法應該可以說是 ZooKeeper 的靈魂了。但是,ZooKeeper 並沒有完全采用 Paxos算法 ,而是使用 ZAB 協議作為其保證數據一致性的核心算法。另外,在ZooKeeper的官方文檔中也指出,ZAB協議並不像 Paxos 算法那樣,是一種通用的分布式一致性算法,它是一種特別為Zookeeper設計的崩潰可恢復的原子消息廣播算法。
2.1.2 ZAB 協議介紹
ZAB(ZooKeeper Atomic Broadcast 原子廣播) 協議是為分布式協調服務 ZooKeeper 專門設計的一種支持崩潰恢復的原子廣播協議。 在 ZooKeeper 中,主要依賴 ZAB 協議來實現分布式數據一致性,基於該協議,ZooKeeper 實現了一種主備模式的系統架構來保持集群中各個副本之間的數據一致性。
2.1.3 ZAB 協議兩種基本的模式:崩潰恢復和消息廣播
ZAB協議包括兩種基本的模式,分別是 崩潰恢復和消息廣播。當整個服務框架在啟動過程中,或是當 Leader 服務器出現網絡中斷、崩潰退出與重啟等異常情況時,ZAB 協議就會進人恢復模式並選舉產生新的Leader服務器。當選舉產生了新的 Leader 服務器,同時集群中已經有過半的機器與該Leader服務器完成了狀態同步之后,ZAB協議就會退出恢復模式。其中,所謂的狀態同步是指數據同步,用來保證集群中存在過半的機器能夠和Leader服務器的數據狀態保持一致。
當集群中已經有過半的Follower服務器完成了和Leader服務器的狀態同步,那么整個服務框架就可以進人消息廣播模式了。 當一台同樣遵守ZAB協議的服務器啟動后加人到集群中時,如果此時集群中已經存在一個Leader服務器在負責進行消息廣播,那么新加人的服務器就會自覺地進人數據恢復模式:找到Leader所在的服務器,並與其進行數據同步,然后一起參與到消息廣播流程中去。正如上文介紹中所說的,ZooKeeper設計成只允許唯一的一個Leader服務器來進行事務請求的處理。Leader服務器在接收到客戶端的事務請求后,會生成對應的事務提案並發起一輪廣播協議;而如果集群中的其他機器接收到客戶端的事務請求,那么這些非Leader服務器會首先將這個事務請求轉發給Leader服務器。
3. Eureka保證AP
Eureka看明白了這一點,因此在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩余的節點依然可以提供注冊和查詢服務。而Eureka的客戶端在向某個Eureka注冊或如果發現連接失敗,則會自動切換至其它節點,只要有一台Eureka還在,就能保證注冊服務可用(保證可用性),只不過查到的信息可能不是最新的(不保證強一致性)。除此之外,Eureka還有一種自我保護機制,如果在15分鍾內超過85%的節點都沒有正常的心跳,那么Eureka就認為客戶端與注冊中心出現了網絡故障,此時會出現以下幾種情況:
1. Eureka不再從注冊列表中移除因為長時間沒收到心跳而應該過期的服務
2. Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用)
3. 當網絡穩定時,當前實例新的注冊信息會被同步到其它節點中
因此, Eureka可以很好的應對因網絡故障導致部分節點失去聯系的情況,而不會像zookeeper那樣使整個注冊服務癱瘓。