ZAB協議的那些事?

1、什麼是zab協議?

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

Zab 協議分爲兩大塊:架構

  • 廣播(boardcast):Zab 協議中,全部的寫請求都由 leader 來處理。正常工做狀態下,leader 接收請求並經過廣播協議來處理。
  • 恢復(recovery):當服務初次啓動,或者 leader 節點掛了,系統就會進入恢復模式,直到選出了有合法數量 follower 的新 leader,而後新 leader 負責將整個系統同步到最新狀態。

    1.1廣播(boardcast)

    廣播的過程其實是一個簡化的二階段提交過程:分佈式

    1. Leader 接收到消息請求後,將消息賦予一個全局惟一的 64 位自增 id,叫作:zxid,經過 zxid 的大小比較便可實現因果有序這一特性。
    2. Leader 經過先進先出隊列(經過 TCP 協議來實現,以此實現了全局有序這一特性)將帶有 zxid 的消息做爲一個提案(proposal)分發給全部 follower。
    3. 當 follower 接收到 proposal,先將 proposal 寫到硬盤,寫硬盤成功後再向 leader 回一個 ACK。
    4. 當 leader 接收到合法數量的 ACKs 後,leader 就向全部 follower 發送 COMMIT 命令,同事會在本地執行該消息。
    5. 當 follower 收到消息的 COMMIT 命令時,就會執行該消息
      廣播過程

      相比於完整的二階段提交,Zab 協議最大的區別就是不能終止事務,follower 要麼回 ACK 給 leader,要麼拋棄 leader,在某一時刻,leader 的狀態與 follower 的狀態極可能不一致,所以它不能處理 leader 掛掉的狀況,因此 Zab 協議引入了恢復模式來處理這一問題。從另外一角度看,正由於 Zab 的廣播過程不須要終止事務,也就是說不須要全部 follower 都返回 ACK 才能進行 COMMIT,而是隻須要合法數量(2f+1 臺服務器中的 f+1 臺) 的follower,也提高了總體的性能。性能

    1.2恢復(recovery)

因爲以前講的 Zab 協議的廣播部分不能處理 leader 掛掉的狀況,Zab 協議引入了恢復模式來處理這一問題。爲了使 leader 掛了後系統能正常工做,須要解決如下兩個問題:設計

  • 已經被處理的消息不能丟
  • 被丟棄的消息不能再次出現

已經被處理的消息不能丟

這一狀況會出如今如下場景:當 leader 收到合法數量 follower 的 ACKs 後,就向各個 follower 廣播 COMMIT 命令,同時也會在本地執行 COMMIT 並向鏈接的客戶端返回「成功」。可是若是在各個 follower 在收到 COMMIT 命令前 leader 就掛了,致使剩下的服務器並無執行都這條消息。日誌

如圖 1-1,消息 1 的 COMMIT 命令 Server1(leader)和 Server2(follower) 上執行了,可是 Server3 尚未收到消息 1 的 COMMIT 命令,此時 leader Server1 已經掛了,客戶端極可能已經收到消息 1 已經成功執行的回覆,通過恢復模式後須要保證全部機器都執行了消息 1。cdn

圖 1-1

爲了實現已經被處理的消息不能丟這個目的,Zab 的恢復模式使用瞭如下的策略:blog

  1. 選舉擁有 proposal 最大值(即 zxid 最大) 的節點做爲新的 leader:因爲全部提案被 COMMIT 以前必須有合法數量的 follower ACK,即必須有合法數量的服務器的事務日誌上有該提案的 proposal,所以,只要有合法數量的節點正常工做,就必然有一個節點保存了全部被 COMMIT 消息的 proposal 狀態。
  2. 新的 leader 將本身事務日誌中 proposal 但未 COMMIT 的消息處理。
  3. 新的 leader 與 follower 創建先進先出的隊列, 先將自身有而 follower 沒有的 proposal 發送給 follower,再將這些 proposal 的 COMMIT 命令發送給 follower,以保證全部的 follower 都保存了全部的 proposal、全部的 follower 都處理了全部的消息。
    經過以上策略,能保證已經被處理的消息不會丟

被丟棄的消息不能再次出現

這一狀況會出如今如下場景:當 leader 接收到消息請求生成 proposal 後就掛了,其餘 follower 並無收到此 proposal,所以通過恢復模式從新選了 leader 後,這條消息是被跳過的。 此時,以前掛了的 leader 從新啓動並註冊成了 follower,他保留了被跳過消息的 proposal 狀態,與整個系統的狀態是不一致的,須要將其刪除。隊列

如圖 1-2 ,在 Server1 掛了後系統進入新的正常工做狀態後,消息 3被跳過,此時 Server1 中的 P3 須要被清除。事務

圖 1-2

Zab 經過巧妙的設計 zxid 來實現這一目的。一個 zxid 是64位,高 32 是紀元(epoch)編號,每通過一次 leader 選舉產生一個新的 leader,新 leader 會將 epoch 號 +1。低 32 位是消息計數器,每接收到一條消息這個值 +1,新 leader 選舉後這個值重置爲 0。這樣設計的好處是舊的 leader 掛了後重啓,它不會被選舉爲 leader,由於此時它的 zxid 確定小於當前的新 leader。當舊的 leader 做爲 follower 接入新的 leader 後,新的 leader 會讓它將全部的擁有舊的 epoch 號的未被 COMMIT 的 proposal 清除。

2、總結

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

相關文章
相關標籤/搜索