1. 程式人生 > 其它 >Zookeeper的ZAB協議

Zookeeper的ZAB協議

前言

Zookeeper 是一個開源的分散式協調服務,提供了分散式資料一致性的解決方案。分散式應用可以基於它實現諸如資料釋出/訂閱、負載均衡、命名服務、分散式協調/通知、分散式鎖和分散式佇列等功能。

ZAB的全稱是Zookeeper Automatic Broadcast,即 Zookeeper 原子廣播協議,一種專門為Zookeeper設計的支援崩潰恢復的原子廣播協議。

基本概念

叢集角色

通常在分散式系統中,構成一個叢集的每一臺機器都有自己的角色,最典型的叢集模式就是 Master/Slave 模式。但是在 Zookeeper 叢集沒有 Master 和 Slave 的概念,取而代之的是如下角色:

  • Leader
    • 在同一個Zookeeper叢集中只能有一個 Leader。
    • Leader 可以提供讀寫功能對 Client,其他 Follower 只提供讀取功能。
  • Follower
    • 同一個叢集中可以有多個 Follower,Follower(Leader也算作Follower)的數量最好是奇數。
    • Follower 提供讀取資料功能對 Client,如果Follower 接收到寫請求,那麼它會轉發這個請求到 Leader。
    • Follower 可以參與叢集的 Leader 選舉。
  • Observer
    • 同一個叢集中可以有多個 Observer,且 Observer 只負責讀取功能,不參與 Leader 選舉過程。

ZooKeeper 在讀取高於寫入的應用中具有特別高的效能,因為寫入操作涉及到同步所有伺服器的狀態。所以一般而言,Zookeeper叢集中,Observer的數量應該最大,Follower和Leader的數量不用太多,但是數量最少也要達到3個節點。

ZXID介紹

Zxid 是一個long型(64位)整數,分為兩部分:epoch(紀元,前32位)和counter(計數器,後32位),是一個全域性有序的數字。

  • epoch
    • epoch值隨著新leader的產生而變化,每當新選舉一個leader,epoch值會自增1。
    • 如果counter已經達到最大值,即後32位全為1,則進位,此時epoch會自增1。
  • counter
    • 每次committed一個proposal,counter值都會自增1。

Zxid分類:

  • cZxid
    • 建立當前節點時的事務ID。
  • mZxid
    • 最近修改當前節點時的事務ID。
  • pZxid
    • 表示當前節點的子節點列表最後一次修改的事務ID。

ZAB協議介紹

ZAB 協議是專門為 Zookeeper 設計的支援崩潰可恢復的原子廣播協議,所以這是一個有特定使用場景的協議,並不具備通用性。

ZAB 協議包括兩種基本的模式:崩潰恢復和訊息廣播。

崩潰恢復和訊息廣播模式會一直保持來回切換。當叢集在啟動過程中、Leader 伺服器崩潰、叢集出現網路中斷或者重啟等異常資訊時,叢集會切換到崩潰恢復模式,選出新的 Leader 伺服器。當 Leader 伺服器啟用成功後,叢集會退出崩潰恢復模式,然後切換到訊息廣播模式。

崩潰恢復(選舉)

關於Zookeeper的選舉有三個問題需要解答:選舉時機、選舉規則和選舉流程

選舉時機

Zookeeper 的選舉時機分成以下幾種情況:

  • 叢集啟動過程中
    • Zookeeper 叢集要求最少有3個可以參與選舉的節點(作為observer的節點不能參與選舉)。
    • 叢集啟動過程中,如果叢集中沒有Leader,那麼叢集就會進入選舉狀態。
  • 叢集執行過程中
    • 如果 Leader 節點崩潰,叢集失去了 Leader 會進入崩潰恢復狀態,開始選舉。
    • 如果叢集發生網路故障,比如Leader 伺服器失去了與過半 Follower的聯絡,叢集就會進入崩潰恢復模式,開始選舉。

選舉規則(選舉演算法)

  • 在啟動過程中選舉leader的情況比較簡單,因為此時整個叢集的所有節點都沒有資料,所以選舉leader依據myid的值,即myid最大的節點當選leader。myid值只要不是-1,其他任何值都可以。

  • 如果叢集已經開始執行,然後進入崩潰恢復模式,此時選舉需要根據以下條件決定(優先順序從高到低):

    • epoch
    • counter
    • myid

    如果一個參與選舉的伺服器的資料的zxid最大,那麼這個伺服器就作為新 Leader。如果所有參與選舉的伺服器的zxid都一致,那麼myid值最大的伺服器當選新 Leader。

資料同步功能:

在成為新 Leader 之後,在正式開始工作之前,新 Leader 還需要做一個同步資料的工作,保證叢集中伺服器的資料一致。首先,Leader 伺服器會為每一個 Follower 伺服器準備一個佇列,然後將那些沒有被各個 Follower 伺服器同步的事務以 proposal 訊息的形式逐個傳送到各個佇列中,並在每一個 proposal 訊息後再發送一個 committed 訊息,以表示該 proposal 已經被提交。等到 Follower 將所有未同步的 proposal 寫入本地檔案中後,返回 ACK 訊息給 Leader 伺服器,該 Follower 伺服器會被加入到 Leader 伺服器可用的 Follower 列表。

同步資料過程中,為了確保正確地同步資料,ZAB 做了如下規定:

  • ZAB 協議需要確保那些已經在 Leader 伺服器上提交的事務proposal最終被所有伺服器提交。
    • 如果proposal 已經被提交,說明該proposal 已經被之前的 quorum 確認,這是一個有效的proposal,所以新 Leader 需要將已經被提交的 committed 的 proposal 同步給所有 Follower。
  • ZAB 協議需要確保丟棄那些只在 Leader 伺服器上被提交的事務。
    • 如果 proposal 沒有被提交,那麼說明該proposal還沒有被之前的 quorum 確認,不是一個正式的proposal,所以新 Leader 不需要同步到其他 Follower,直接丟棄即可。

選舉流程

  1. 通過畫圖解決

訊息廣播

ZAB 協議的訊息廣播過程使用了原子廣播協議,類似一個二階段提交過程。

  • 第一階段
    • 針對客戶端的請求,Leader 節點為請求生成一個proposal,然後將proposal傳送到所有Follower的佇列中。
    • 然後收集從Follower返回的 ACK 確認資訊。
      • 如果返回的ACK確認資訊票數超過了 N/2 +1,那麼就進入第二階段。
      • 如果返回的ACK確認資訊票數沒有超過 N/2 +1 ,那麼這個proposal就被丟棄。
  • 第二階段
    • 如果針對某一個 proposal,Leader 已經收到了足夠的 ACK 票數,那麼 Leader 會發送 committed 資訊給所有的 Follower,仍舊傳送到各個 Follower 的佇列中。
    • Follower 收到 committed 訊息後將對應的proposal入庫,即寫入本地的日誌檔案中。

和二階段提交不同,ZAB 協議的二階段提交不需要等待所有的Follower返回 ACK 訊息後才進行第二階段的committed操作,只需要超過 N/2 +1 的節點返回 ACK 資訊即可。

在整個訊息廣播過程中,如果發生了 Leader 崩潰或者Leader和Followers之間的網路不通,那麼整個叢集就會進入崩潰恢復模式,防止發生整個叢集資料不一致的問題。進入崩潰恢復模式後,叢集會重新選擇 Leader,然後同步資料。

如果之前的Leader 又重新連入的網路,那麼該節點也只能作為Follower加入叢集,即使該節點有值更大的 zxid,那麼這些proposal也只能被丟棄。