Zookeeper ZAB 協議分析

前言

ZAB 協議是爲分佈式協調服務 ZooKeeper 專門設計的一種支持崩潰恢復的原子廣播協議。在 ZooKeeper 中,主要依賴 ZAB 協議來實現分佈式數據一致性,基於該協議,ZooKeeper 實現了一種主備模式的系統架構來保持集羣中各個副本之間的數據一致性。算法

Atomic broadcast protocol

ZAB 是 Zookeeper 原子廣播協議的簡稱,下面咱們來討論協議的內容,注意:理論與實現是有區別的,若是你對協議的理論不感興趣,能夠直接跳過看實現。服務器

問題的提出

Zookeeper 客戶端會隨機鏈接到 Zookeeper 集羣的一個節點,若是是讀請求,就直接從當前節點中讀取數據;若是是寫請求,那麼節點就會向 leader 提交事務,leader 會廣播事務,只要有超過半數節點寫入成功,該寫請求就會被提交(類 2PC 協議)。架構

那麼問題來了:分佈式

  • 主從架構下,leader 崩潰,數據一致性怎麼保證?
  • 選舉 leader 的時候,整個集羣沒法處理寫請求的,如何快速進行 leader 選舉?

帶着這兩個問題,咱們來看看 ZAB 協議是如何解決的。atom

ZAB 的四個階段

術語解釋

  • quorum:集羣中超過半數的節點集合

ZAB 中的節點有三種狀態設計

  • following:當前節點是跟隨者,服從 leader 節點的命令
  • leading:當前節點是 leader,負責協調事務
  • election/looking:節點處於選舉狀態

代碼實現中多了一種:observing 狀態,這是 Zookeeper 引入 Observer 以後加入的,Observer 不參與選舉,是隻讀節點,跟 ZAB 協議沒有關係日誌

節點的持久狀態code

  • history:當前節點接收到事務提議的 log
  • acceptedEpoch:follower 已經接受的 leader 更改年號的 NEWEPOCH 提議
  • currentEpoch:當前所處的年代
  • lastZxid:history 中最近接收到的提議的 zxid (最大的)

在 ZAB 協議的事務編號 Zxid 設計中,Zxid 是一個 64 位的數字,其中低 32 位是一個簡單的單調遞增的計數器,針對客戶端每個事務請求,計數器加 1;而高 32 位則表明 Leader 週期 epoch 的編號,每一個當選產生一個新的 Leader 服務器,就會從這個 Leader 服務器上取出其本地日誌中最大事務的ZXID,並從中讀取 epoch 值,而後加 1,以此做爲新的 epoch,並將低 32 位從 0 開始計數。server

epoch:能夠理解爲當前集羣所處的年代或者週期,每一個 leader 就像皇帝,都有本身的年號,因此每次改朝換代,leader 變動以後,都會在前一個年代的基礎上加 1。這樣就算舊的 leader 崩潰恢復以後,也沒有人聽他的了,由於 follower 只遵從當前年代的 leader 的命令。*blog

Phase 0: Leader election(選舉階段)

節點在一開始都處於選舉階段,只要有一個節點獲得超半數節點的票數,它就能夠當選準 leader。只有到達 Phase 3 準 leader 纔會成爲真正的 leader。這一階段的目的是就是爲了選出一個準 leader,而後進入下一個階段。

協議並無規定詳細的選舉算法,後面咱們會提到實現中使用的 Fast Leader Election。

Phase 1: Discovery(發現階段)

在這個階段,followers 跟準 leader 進行通訊,同步 followers 最近接收的事務提議。這個一階段的主要目的是發現當前大多數節點接收的最新提議,而且準 leader 生成新的 epoch,讓 followers 接受,更新它們的 acceptedEpoch
phase 1
一個 follower 只會鏈接一個 leader,若是有一個節點 f 認爲另外一個 follower p 是 leader,f 在嘗試鏈接 p 時會被拒絕,f 被拒絕以後,就會進入 Phase 0。

Phase 2: Synchronization(同步階段)

同步階段主要是利用 leader 前一階段得到的最新提議歷史,同步集羣中全部的副本。只有當 quorum 都同步完成,準 leader 纔會成爲真正的 leader。follower 只會接收 zxid 比本身的 lastZxid 大的提議。
phase 2

Phase 3: Broadcast(廣播階段)

到了這個階段,Zookeeper 集羣才能正式對外提供事務服務,而且 leader 能夠進行消息廣播。同時若是有新的節點加入,還須要對新節點進行同步。
phase 3
值得注意的是,ZAB 提交事務並不像 2PC 同樣須要所有 follower 都 ACK,只須要獲得 quorum (超過半數的節點)的 ACK 就能夠了。

協議實現

協議的 Java 版本實現跟上面的定義有些不一樣,選舉階段使用的是 Fast Leader Election(FLE),它包含了 Phase 1 的發現職責。由於 FLE 會選舉擁有最新提議歷史的節點做爲 leader,這樣就省去了發現最新提議的步驟。實際的實現將 Phase 1 和 Phase 2 合併爲 Recovery Phase(恢復階段)。因此,ZAB 的實現只有三個階段:

  • Fast Leader Election
  • Recovery Phase
  • Broadcast Phase

Fast Leader Election

前面提到 FLE 會選舉擁有最新提議歷史(lastZixd最大)的節點做爲 leader,這樣就省去了發現最新提議的步驟。這是基於擁有最新提議的節點也有最新提交記錄的前提。

成爲 leader 的條件

  1. epoch最大的
  2. epoch相等,選 zxid 最大的
  3. epochzxid都相等,選擇server id最大的(就是咱們配置zoo.cfg中的myid

節點在選舉開始都默認投票給本身,當接收其餘節點的選票時,會根據上面的條件更改本身的選票並從新發送選票給其餘節點,當有一個節點的得票超過半數,該節點會設置本身的狀態爲 leading,其餘節點會設置本身的狀態爲 following。

選舉過程

FLE

Recovery Phase (恢復階段)

這一階段 follower 發送它們的 lastZixd 給 leader,leader 根據 lastZixd 決定如何同步數據。這裏的實現跟前面 Phase 2 有所不一樣:Follower 收到 TRUNC 指令會停止 L.lastCommittedZxid 以後的提議,收到 DIFF 指令會接收新的提議。

history.lastCommittedZxid:最近被提交的提議的 zxid
history:oldThreshold:被認爲已經太舊的已提交提議的 zxid

Recovery Phase

總結

通過上面的分析,咱們能夠來回答開始提到的兩個問題

  • 主從架構下,leader 崩潰,數據一致性怎麼保證?leader 崩潰以後,集羣會選出新的 leader,而後就會進入恢復階段,新的 leader 具備全部已經提交的提議,所以它會保證讓 followers 同步已提交的提議,丟棄未提交的提議(以 leader 的記錄爲準),這就保證了整個集羣的數據一致性。
  • 選舉 leader 的時候,整個集羣沒法處理寫請求的,如何快速進行 leader 選舉?這是經過 Fast Leader Election 實現的,leader 的選舉只須要超過半數的節點投票便可,這樣不須要等待全部節點的選票,可以儘早選出 leader。

這篇文章是根據我對 ZAB 協議的理解寫成的,若是以爲有些細節沒有講清楚,能夠看後面的參考資料,我主要是參考這篇論文的。

參考資料
ZooKeeper’s atomic broadcast protocol:Theory and practice

原文:http://blog.jobbole.com/104985/

相關文章
相關標籤/搜索