深入理解Zookeeper系列(1):ZAB協議

1. 關于Zookeper

??ZooKeeper是一個集中服務,用于維護配置信息,命名,提供分布式同步和提供組服務。 所有這些類型的服務都以某種形式被分布式應用程序使用。 每次實施服務時,都會有很多工作來解決不可避免的錯誤和競爭條件。 由于實施這些服務的困難,最初的應用程序通常會不穩定,這使得它們在變化和難以管理的情況下變得脆弱。 即使正確完成,這些服務的不同實現會導致部署應用程序時的管理復雜性。而Apache ZooKeeper致力于開發和維護一個開源服務器,從而實現高度可靠的分布式協調。

ZooKeeper允許分布式進程通過與標準文件系統組織類似的共享分層名稱空間相互協調。名稱空間由znodes組成,它們與文件和目錄類似---ZooKeeper Wiki

Zookeeper的架構圖如下:


image.png

2. Zab協議

ZooKeeper支持客戶端讀取和更新具有高可用性的鍵值對。通過將數據復制到多個節點并讓客戶端從任何節點讀取來實現高可用性。

要理解Zookeeper,首先得熟悉它的協議,Zookeeper的協議就是Zookeeper Atomic Broadcast (ZAB).Zab協議由4個階段組成,先來看下總體的層次.

  • Phase 0 – Leader選舉(選出Leader)
  • Phase 1 – 發現(發現全局最新的事務)
  • Phase 2 – 同步(各個Follower同步最新的事務)
  • Phase 3 – 廣播(正常工作的流程)
image.png

術語定義

  • history:已經被接收的提案的日志信息(已經完成的事務的記錄)
  • acceptedEpoch:接受到的最后一個NEWEPOCH消息的epoch。此時此刻所在的Epoch(準Leader生成后就生成的Epoch)。
  • currentEpoch:接受到的最后一個NEWLEADER消息的epoch(注意是Leader發過來的)(生成新的Leader之前所在的舊Leader的Epoch)
  • lastZxid:history中最后一個提案的ZXID編號
  • ZXID通常由64位組成。高32位表示Epoch值,翻譯過來指朝代。就是每次換了Leader之后,Epoch值都會增加1,用來表示所在的周期,方便Follower進程區別現在的Leader。由于有些Leader由于網絡原因會與Follower斷開聯系,當它連上后,現在已經有了Leader,那么它就不能是Leader.Follower會根據Epoch值來判斷當前的Leader。而后32位用來表示Zxid值。每當處理完一個事務,Epoch值都會增加1。而當重新選了一個Leader,那么Zxid重新開始計數。

3. ZAB協議實現的前提條件

  • 完整性(Integrity )
    進程Pj如果收到來自進程Pi的消息m,那么進程Pi—定發送了消息m。
  • 前置性(Prefix)
    如果進程Pj收到了消息m,那么存在這樣的消息m':如果消息m'是消息m的前置消息,那么Pj務必先接收到消息m',然后再接收到消息m。我們將存在這種前置性關系的兩個消息表示為m'm。前置性是整個協議設計中最關鍵的一點,由于每一個消息都有可能是基于之前的消息來進行的,因此所有的消息都必須按照嚴格的先后順序來進行處理。

4. 各個階段詳解

詳細的算法步驟可以參考http://www.tcs.hut.fi/Studies/T-79.5001/reports/2012-deSouzaMedeiros.pdf

  • 階段0: Leader Election(Leader選舉階段)

下篇文章將會講到FLE算法.

?? ?? ??ZooKeeper原來采用了三種選舉算法,后來,淘汰了兩種,只剩下FLE這種算法。使用FLE算法的目的,就是要選出具有最大提交歷史的節點作為候選Leader,這樣后續的日志就只需要考慮候選Leader到其Fellower節點的單向同步就可以保證一致性了。在FLE算法中通過篩選具有最大LastZxid(history中最后一個提案的ZXID編號)的節點作為候選Leader,因為具有最大LastZxid的節點肯定具有最全的提交歷史。
?? ?? 在FLE算法中,每個節點都只能投一張選票,只有這樣才能確定過半選票的統計值,其思路就是在投票的過程中,節點之間互相交換信息,然后節點根據自己獲得的信息(發現更好的候選者)不斷地更新自己手中的選票,更新的標準就是具有更新的提案號:要么具有更新的epoch,或者在相同epoch下具有更大的機器編號。那么這個迭代更新的過程什么時候結束呢?
?? ??首先,每一輪的選取會有一個遞增的round number作為標識,這個值越高優先級越高;其次,每一個節點都有一個狀態標識自己:election和leading/fellowing,同時每個節點都知道集群中其他節點的個數,以及和他們通信的方式。選舉剛剛開始的時候,每個節點在沒有先驗信息的情況下都把選票投向自己,并把這個消息發送給所有的節點,然后等待其他節點們的響應,節點再收到這個消息的時候:
  (1). 如果選票的round number比較舊,則忽略;
  (2). 如果選票的round number比自己新,則更新自己的round number,并清空上一輪相關的陳舊信息,開始廣播自己新的選票;
  (3). 如果是在同一輪投票中:如果接收到的選票的角色是election,并且該消息附帶更新的提案號,則更新自己的選票并繼續廣播自己的選票;如果收到的選票角色是election,但是消息的提案號比自己舊或者跟自己一樣,則記錄這張選票,而檢查發現自己得到針對某個節點超過集群半數的選票,自己切換為leading/fellowing狀態,并轉入Phase Recovery;
?? ?? ?? (4). 任何時候一旦收到leading/fellowing的選票,都指明當前集群中已有有效的候選Leader了,直接更新自己切換入Phase Recovery階段;

  • 階段1: Discovery(發現最后的事務)

??在這個階段,這個階段選出的準Leader(prospective leader)肯定是集群中過半數機器的投票選出的leader。此時所有節點會把自己的F:acceptedEpoch通過FOLLOWERINFO發送給自己的prospective leader,當那個候選Leader得到過半的FOLLOWERINFO消息時候,會在收到消息中取出所見最大的epoch并將其遞增,這樣之前的Leader就不能再提交新的提案了,然后該候選Leader再將這個新epoch通過NEWEPOCH消息發回給這些節點并等待確認。

??在Fellower節點收到候選Leader發送NEWEPOCH后,將其與自己本地的acceptedEpoch對比,如果比他們大就更新自己acceptedEpoch,并返回ACKEPOCH消息后進入Phase 2,否則切換會Phase 0狀態。候選Leader也只能在收到過半數目的ACKEPOCH才會進入Phase 2。需要注意的是這里Fellower發送的ACKEPOCH包含了額外的重要信息——自己最新提交日志,這樣候選Leader在收集ACKEPOCH的同時就知道哪個Fellower具有最新提交了,選定到這個具有最新提交的Fellower后向其同步日志。算法和第一階段消息交流示意圖如圖3.1。

①:各個Follower將 FOLLOWERINFO發送給自己的prospective leader(讓Leader來發現最新的事務)
②:候選Leader選出最新的Epoch并將這個新epoch通過NEWEPOCH消息發回給這些節點并等待確認。(把最新的Epoch返回給Follower)
③: Fellower節點收到候選Leader發送NEWEPOCH后,將其與自己本地的acceptedEpoch對比,如果比他們大就更新自己acceptedEpoch,并返回ACKEPOCH消息(把自己的事務上傳)。


未命名文件.png

階段1算法.png
  • 階段2: Synchronization(同步階段)

??進入這個階段后,候選Leader已經確立了最新任期號和最新提交日志,然后他會把自己的history通過新epoch作為NEWLEADER消息發送給所有的集群成員,集群成員更新自己currentEpoch 并按需同步history信息。完成這個步驟后候選Fellower向Leader發送ACKNEWLEADER消息,而候選Leader得到過半數目的ACKNEWLEADER消息后,會向所有的Fellower發送COMMIT并進入Phase 3,而Fellower接收到COMMIT命令而完成提交后,也會切換到Phase 3。第二階段消息交流信息圖示意圖如下:

①:準Leader發送NewLeader(e’,history) 給follower,方便follower同步最新的事務,從而與Leader一致,達到一致。
②:Follower在收到準Leader的NewLeader(e’,history),它會對它本地的事務,如果需要更新的本地的事務,則更新。更新完之后,發送一個確認消息給準Leader。表明它已經收到。
③準Leader在收到確認信息后,再發送一個commit消息給Follower,通知他們可以提交事務了。Follower在收到之后,完成提交就可以。


image.png

階段二算法
  • 階段3: Broadcast (完成同步后,成員各自完成自己角色的任務)

??到達這個階段后,所有節點檢查自己的prospective leader,如果發現它是自己,就切換到正式Leader的狀態,不是這種情況的節點切換到正式Fellower的狀態,而一致性協議保證此時只可能會有一個Leader。這是整個集群穩定工作狀態,穩定之后的基本流程也類似于上面提到的Propose-ACK-COMMIT的偽2PC(與標準的2PC有區別)操作。其中2PC是指參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。消息傳播示意圖如3.3。

①:客戶端發動事務請求給服務端Leader
②: Leader發送請求執行給每個Follower,讓Follower執行事務。并把do,undo寫入日志。
③:Follower執行事務,并把事務歷史寫入到日志中去,方便以后撤銷。并返回事務是否執行成功給Leader。
④:Leader若收到超過半數Follower消息,則發送commit消息,讓所有的Follower提交事務。否則,發送消息讓所有的Follwer回滾事務


image.png

階段3算法

NOTE: 在這個過程中,如果有新的Follower加入,則Leader把最新的Epoch,以及最新的歷史提交記錄發送給Follower,方便同步.

5. 總結

從上面的協議過程看來,整個ZooKeeper只要保持有一半以上的機器保持正常運行,那么整個集群的功能還是正常的,不會崩潰.而這得益于一偽2pc的過程,只要一半以上的投票,就可以做出決定.

參考文章:
You Cannot Have Exactly-Once Delivery
ZooKeeper’s Atomic Broadcast Protocol: Theory and Practice
Architecture of ZAB – ZooKeeper Atomic Broadcast protocol
ZooKeeper’s atomic broadcast protocol:Theory and practice

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 概述 ZAB (Zookeeper Atomic Broadcast)協議是為分布式協調服務 ZooKeeper ...
    jiangmo閱讀 3,040評論 0 3
  • 最近在學習ZooKeeper,一直想寫篇相關博文記錄下學習內容,礙于自己是個拖延癥重度患者總是停留在準備階段,直到...
    Lexus90511閱讀 7,981評論 5 14
  • 一個真正的寫數據流程是怎么樣的?一個真正的讀數據流程是怎么樣的?一個真正的同步數據流程是怎么樣的?從哪里到哪里?什...
    時待吾閱讀 4,057評論 0 14
  • 端午節,相傳是紀念屈原、伍子胥、曹娥、的。 “屈原是我國文學史上第一位偉大的愛國詩人。戰國末期楚國丹陽(今湖北秭歸...
    江原兒閱讀 403評論 0 0
  • 今天在北京廣安門醫院進修的陳同學給我打來了電話,他說他的心思亂糟糟的。一段寒暄之后,我們切入了主題。 原來是他家里...
    舞傾城夏閱讀 269評論 0 1