ZAB協議簡介

Zookeeper 使用 Zookeeper Atomic Broadcast (ZAB) 協議來保障分佈式數據一致性。html

ZAB是一種支持崩潰恢復的消息廣播協議,採用相似2PC的廣播模式保證正常運行時性能,並使用基於 Paxos 的策略保證崩潰恢復時的一致性。算法

在閱讀本文前建議先了解2PC和Paxos服務器

ZAB協議中節點存在四種狀態:網絡

  • Leading: 當前節點爲集羣 Leader,負責協調事務
  • Following: 當前節點爲 Follower 在 Leader 協調下執行事務
  • Looking: 集羣沒有正在運行的 Leader, 正處於選舉過程
  • Observing: 節點跟隨 Leader 保存系統最新的狀態提供讀服務,但不參與選舉和事務投票

由於 Observing 節點不參與事務和選舉,所以下文所述節點不包括 Observing 節點分佈式

ZAB協議存在兩種工做模式:性能

  • 廣播模式: 當集羣正常運行過程當中,Leader 使用廣播模式保證各 Follower 節點的一致性
  • 恢復模式: 集羣啓動或 Leader 崩潰時系統進入恢復模式,選舉 Leader 並將集羣中各節點的數據同步到最新狀態

Zookeeper 集羣中每一個節點都會存儲系統數據的完整副本,能夠獨立處理讀請求。atom

當 Follower 收到寫請求時會將其轉發給 Leader, Leader 爲每一個寫請求分配惟一的全局有序的事務ID(Zookeeper Transaction Id, ZXID)。日誌

Leader 在廣播模式下協調各 Follower 完成事務,並保證集羣更新到一致的狀態。htm

一致性保證blog

ZAB協議保證集羣的順序一致性而不保證強一致性。

即 Leader 依次完成兩個事務 A、B 時,不能保證全部 Follower 當即更新到最新狀態(不保證強一致性); 只保證全部 Follower 必定時間內會同步到最新狀態(保證最終一致性),且任意 Follower 都認爲事務A先於事務B完成,不會亂序(保證全局順序一致性)。

此外,ZAB協議保證來自同一個 Follower 的兩個事務 A、B 按照 Follower 發出請求的順序(而非 Leader 收到請求的順序)依次執行,不會出現亂序。即保證任意客戶端寫請求的一致性。

ZXID

ZXID 是 Zookeeper 集羣中事務的惟一標識,保證全局有序。

ZXID 是一個 64 位整數, 高32位爲週期號(epoch), 每一個 Leader 被選舉後都會增長 epoch 與上任 Leader 區分。低32位是 Leader 開始事務時分配的遞增編號。

ZXID 中的 epoch 能夠保證 Leader 崩潰從新選舉後被丟棄的事務不會繼續執行。

廣播模式

廣播模式是一個移除了中斷邏輯的2PC協議:

  1. Leader 收到寫請求後爲其分配一個 ZXID 並生成提案發送給全部 Follower
  2. Follower 收到提案後寫事務日誌但不提交,成功後返回 ACK 告知 Leader 能夠進行提交。
  3. Leader 收到過半 Follower 的 ACK 響應後發出 commit 請求執行提交
  4. Leader 收到過半 Follower 對 commit 請求的 ACK 響應後便認爲事務已完成。剩餘的 Follower 則會放棄執行這次事務,進入數據同步階段,與集羣達成一致。

ZAB廣播模式相對於完整的2PC移除了中斷邏輯, 且只要過半 Follower 完成便可不須要等待所有 Follower。

崩潰或網絡超時的 Follower 能夠直接拋棄 Leader,並在數據同步階段與集羣達成一致,這種作法提升了集羣的性能。

由於沒法保證全部 Follower 都完成了提交,因此 Zookeeper 沒法保證強一致性。

Leader 爲每一個 Follower 的寫請求維護了一個 FIFO 隊列以保證順序一致性,具體實現方式是根據 TCP 報文的序列號肯定請求的前後順序。

恢復模式

當集羣啓動或者Leader崩潰時,Zookeeper 集羣會進入恢復模式選舉新的 Leader 並將集羣同步至最新狀態。

Leader 與過半的 Follower 沒法正常通訊即視爲崩潰

在崩潰恢復過程當中須要保證:

  • 已執行的事務不能丟失(Never forget delivered messages)
  • 未執行的事務不能繼續執行(Let go of messages that are skipped)

若 Leader 在 commit 階段崩潰,根據已完成的事務不能丟失的原則,這些事務應該繼續完成。

由於集羣中 ZXID 最大的提案是 Leader 崩潰前發出的最新的提案,因此應選擇擁有 ZXID 最大的提案的節點作爲新的 Leader。

新 Leader 會將自身日誌中全部未提交事務從新生成提案並協調集羣將其完成, 保證全部被髮送的消息(delivered messages)都被處理。

若 Leader 在 proposal 階段崩潰,根據未執行的事務不能繼續的原則,節點應當丟棄這些事務。

當新 Leader 被選舉以後會增長 ZXID 的 epoch 值,所以 epoch 值較小的提案能夠直接丟棄。

恢復模式分爲兩個階段:選舉階段和恢復階段。

上文已經說明恢復階段的任務是 Leader 將未提交事務從新生成提案並協調集羣將其完成,再也不贅述。

選舉過程

選舉要保證:

  • 集羣中有且只有一個節點做爲 Leader, 該 Leader 能夠與集羣中過半節點通訊
  • 新 Leader 擁有 ZXID 最大的提案

在3.4.0後的Zookeeper的版本只保留了TCP版本的FastLeaderElection選舉算法

每張選票包含3條信息:

  • vote_sid: 推舉的服務器ID
  • vote_zxid: 推舉的服務器的最大ZXID
  • epoch: 投票的輪數

發起選舉的節點會向全部可通訊節點發送第一張選票,推舉本身做爲 Leader。

收到選票的服務器根據下列規則決定本身的投票:

  • 若 epoch 大於自身 epoch 說明上一輪投票已結束,更新自身 epoch 值加入新一輪投票,並清除已結束輪次的數據。
  • 選擇自身已知 擁有最大ZXID 的服務器做爲 Leader。即服務器本地保存(vote_sid, vote_zxid)並初始化爲自身(sid, zxid), 若收到的選票中 vote_zxid 更大就更新本地數據,並根據最新數據投出選票。
  • 若存在 zxid 相同則選擇 sid 最大的服務器(做者認爲選擇sid最小的也能夠)。

若在某輪投票中某個節點收到過半數的相同選票,那麼認爲該服務器爲新的 Leader 投票結束。

由於選舉階段要求服務器收到過半選票才能成爲新 Leader, 所以不可能出現集羣中存在兩個 Leader 的現象。

選舉過程是比較典型的 Paxos 算法過程,選舉過程當中不會產生新的 ZXID, 所以不會出現 Paxos 算法中活鎖的現象。


關於ZAB協議的詳細內容能夠閱讀官方論文ZooKeeper’s atomic broadcast protocol: Theory and practice

相關文章
相關標籤/搜索