同窗們,在上一章中,咱們主要講了Zookeeper兩種啓動模式以及具體如何搭建。本章內容主要講的是集羣相關的原理內容,第一章能夠當作是Zookeeper原理篇的基礎部分,本章則是Zookeeper原理篇進階部分,有關於Zookeeper集羣的讀寫機制、ZAB協議的知識解析。html
本篇的內容主要包含如下幾點:數據庫
接下來咱們來講一說Zookeeper的集羣架構。apache
第一章提過,Zookeeper中,能改變ZooKeeper服務器狀態的操做稱爲事務操做。通常包括數據節點建立與刪除、數據內容更新和客戶端會話建立與失效等操做。服務器
Zookeeper 經過複製來實現高可用。在上一章提到的集羣模式(replicated mode)下,以Leader
節點爲準,Zookeeper的ZNode
樹上面的每個修改都會被同步(複製)到其餘的Server 節點上面。網絡
上面實際上只是一個概念性的簡單敘述,在看完下文的讀寫機制和ZAB協議的兩種模式以後,你就會對這幾種角色有一個更加深入的認識。架構
下圖就是集羣模式下一個Zookeeper Server節點提供讀寫服務的一個流程。分佈式
如上圖所示,每一個Zookeeper Server節點除了包含一個請求處理器來處理請求之外,都會有一個**內存數據庫(ReplicatedDatabase)**用於持久化數據。ReplicatedDatabase 包含了整個Data Tree。微服務
來自於Client的讀服務(Read Requst),是直接由對應Server的本地副原本進行服務的。性能
至於來自於Client的寫服務(Write Requst),由於Zookeeper要保證每臺Server的本地副本是一致的(單一系統映像),須要經過一致性協議(後文提到的ZAB協議)來處理,成功處理的寫請求(數據更新)會先序列化到每一個Server節點的本地磁盤(爲了再次啓動的數據恢復)再保存到內存數據庫中。學習
集羣模式下,Zookeeper使用簡單的同步策略,經過如下三條基本保證來實現數據的一致性:
全局串行化全部的寫操做
串行化能夠把變量包括對象,轉化成連續bytes數據. 你能夠將串行化後的變量存在一個文件裏或在網絡上傳輸. 而後再反串行化還原爲原來的數據。
保證同一客戶端的指令被FIFO執行(以及消息通知的FIFO)
FIFO -先入先出
自定義的原子性消息協議
簡單來講,對數據的寫請求,都會被轉發到Leader節點來處理,Leader節點會對此次的更新發起投票,而且發送提議消息給集羣中的其餘節點,當半數以上的Follower節點將本次修改持久化以後,Leader 節點會認爲此次寫請求處理成功了,提交本次的事務。
Zookeeper 的核心思想就是,提供一個非鎖機制的Wait Free 的用於分佈式系統同步的核心服務。其核心對於文件、數據的讀寫服務,並不提供加鎖互斥的服務。
可是因爲Zookeeper的每次更新操做都會更新ZNode的版本(詳見第一章),也就是客戶端能夠本身基於版本的對比,來實現更新數據時的加鎖邏輯。例以下圖。
就像咱們更新數據庫時,會新增一個version字段,經過更新先後的版本對比來實現樂觀鎖。
終於到了ZAB協議,講述完ZAB協議,你們對Zookeeper的一些特性會有更深的體會,對本文的其餘內容也會有更透徹的理解。
ZAB 協議是爲分佈式協調服務ZooKeeper專門設計的一種支持崩潰恢復的一致性協議,這個機制保證了各個server之間的同步。全稱 Zookeeper Atomic Broadcast Protocol - Zookeeper 原子廣播協議。
Zab協議有兩種模式,它們分別是恢復模式和廣播模式。
廣播模式相似於分佈式事務中的 Two-phase commit (兩階段式提交),由於Zookeeper中一次寫操做就是被當作一個事務,因此這實際上本質是相同的。
在廣播模式,一次寫請求要經歷如下的步驟
Leader
節點Leader
節點先將更新持久化到本地Leader
節點將這次更新提議(propose)給Followers
,進入收集選票的流程Follower
節點接收請求,成功將修改持久化到本地,發送一個ACK給Leader
Leader
接收到半數以上的ACK時,Leader
將廣播commit消息並在本地deliver該消息。Leader
發來的commit消息時,Follower
也會deliver該消息。廣播協議在全部的通信過程當中使用TCP的FIFO信道,經過使用該信道,使保持有序性變得很是的容易。經過FIFO信道,消息被有序的deliver。只要收到的消息一被處理,其順序就會被保存下來。
可是這種模式下,若是Leader
自身發生了故障,Zookeeper的集羣不就提供不了寫服務了嗎?這就引入了下面的恢復模式。
簡單點來講,當集羣中的Leader
故障或者服務啓動的時候,ZAB就會進入恢復模式,其中包括Leader
選舉和完成其餘Server和Leader
之間的狀態同步。
NOTE:選主是ZAB協議中最爲重要和複雜的過程。這裏面的概念知識較多,放在本章一塊兒講反而不利於理解本章的知識,因此我打算在下一章單獨介紹,同窗們能夠選擇性地食用。
一個集羣的可伸縮性便可以引入更多的集羣節點,來提高某種性能。Zookeeper實際上就是提供讀服務和寫服務。在最先的時候,Zookeeper是經過引入Follower
節點來提高讀服務的性能。可是根據咱們以前學習過的讀寫機制和ZAB協議的內容,引入新的Follower
節點,會形成Zookeeper 寫服務的降低,由於Leader
發起的投票是要半數以上的Follower
節點響應纔會成功,你Follower
多了,就增長了協議中投票過程的壓力,可能會拖慢整個投票響應的速度。結果就是,Follower
節點增長,集羣的寫操做吞吐會降低。
在這種狀況下,Zookeeper 在3.3.3版本以後,在集羣架構中引入了Observer
角色,和Follower
惟一的區別的就是不參與投票不參與選主。這樣既提高了讀性能,又不會影響寫性能。
另外提一句,Zookeeper的寫性能是不能被擴展的,這也是他不適合當作服務註冊發現中心的一個緣由之一,在服務發現和健康監測場景下,隨着服務規模的增大,不管是應用頻繁發佈時的服務註冊帶來的寫請求,仍是刷毫秒級的服務健康狀態帶來的寫請求,都會Zookeeper帶來很大的寫壓力,由於它自己的寫性能是沒法擴展的。後文引的文章會詳細介紹。
分佈式領域中存在CAP理論:
C:Consistency,一致性,數據一致更新,全部數據變更都是同步的。
A:Availability,可用性,系統具備好的響應性能。
P:Partition tolerance,分區容錯性。以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇,也就是說不管任何消息丟失,系統均可用。
該理論已被證實:任何分佈式系統只可同時知足兩點,沒法三者兼顧。 所以,將精力浪費在思考如何設計能知足三者的完美系統上是愚鈍的,應該根據應用場景進行適當取捨。
根據咱們前面學習過的讀寫機制和ZAB協議的內容,Zookeeper本質應該是一個偏向CP的分佈式系統。由於廣播協議本質上是犧牲了系統的響應性能的。另外從它的如下幾個特色也能夠看出。也就是在第一章最後提出的幾個特色。
① 順序一致性 從同一個客戶端發起的事務請求,最終將會嚴格按照其發起順序被應用到ZooKeeper中。
② 原子性 全部事務請求的結果在集羣中全部機器上的應用狀況是一致的,也就是說要麼整個集羣全部集羣都成功應用了某一個事務,要麼都沒有應用,必定不會出現集羣中部分機器應用了該事務,而另一部分沒有應用的狀況。
③ 單一視圖 不管客戶端鏈接的是哪一個ZooKeeper服務器,其看到的服務端數據模型都是一致的。
④ 可靠性 一旦服務端成功地應用了一個事務,並完成對客戶端的響應,那麼該事務所引發的服務端狀態變動將會被一直保留下來,除非有另外一個事務又對其進行了變動。
直接引一篇阿里中間件的文章吧,講的比我好。實際在生產狀況下,大多數公司沒有達到像大公司那樣的微服務量級,Zookeeper是徹底能知足服務註冊中心的需求的。
本章主要介紹了Zookeeper的集羣架構,詳述了ZK的幾種角色和組件,還介紹了Zookeeper的讀寫機制和最核心的ZAB協議,最後對其餘一些比較雜的知識點統一歸在一塊兒討論了一下。
本章的知識我本人認爲信息量仍是蠻大的,整理完以後我本身對Zookeeper集羣服務的機制原理有了更深的體會。閱讀時最好可以結合第一章的一些基礎概念,這樣更有助於理解,讓知識點先後呼應。但願能對你理解Zookeeper起到幫助。
下一章我會詳細介紹本章未介紹的Zookeeper選主過程(Leader Election)。
[1] <zookeeper.apache.org/doc/r3.4.13… 官方文檔
[3] www.cnblogs.com/sunddenly/p…
[4] CAP 定理的含義 -- 阮一峯