1. 程式人生 > >分散式理論系列(三)ZAB 協議

分散式理論系列(三)ZAB 協議

分散式理論系列(三)ZAB 協議

在學習了 Paxos 後,接下來學習 Paxos 在開源軟體 Zookeeper 中的應用。

一、Zookeeper

Zookeeper 致力於提供一個高效能、高可用,且具有嚴格的順序訪問控制能力(主要是寫操作的嚴格順序性)的分散式協調服務。高效能使得 Zookeeper 能夠應用於那些對系統吞吐有明確要求的大型分散式系統中,高可用使得分散式的單點問題得到了很好的解決,而嚴格的順序訪問控制使得客戶端能夠基於 Zookeeper 實現一些複雜的同步原語(Zxid)。

  1. 簡單的資料模型:
    Zookeeper 使得分散式程式能夠通過一個共享的樹形結構的名字空間來進行相互協調,即 Zookeeper 伺服器記憶體中的資料模型由一系列被稱為 ZNode 的資料節點組成,Zookeeper 將全量的資料儲存在記憶體中,以此來提高伺服器吞吐、減少延遲的目的。

  2. 可構建叢集:
    一個 Zookeeper 叢集通常由一組機器構成,組成 Zookeeper 叢集的而每臺機器都會在記憶體中維護當前伺服器狀態,並且每臺機器之間都相互通訊。

  3. 順序訪問:
    對於來自客戶端的每個更新請求,Zookeeper 都會分配一個全域性唯一的遞增編號,這個編號反映了所有事務操作的先後順序。

  4. 高效能:
    Zookeeper 將全量資料儲存在記憶體中,並直接服務於客戶端的所有非事務請求,因此它尤其適用於以讀操作為主的應用場景。

二、ZAB (原子訊息廣播協議)

ZAB (ZooKeeper Atomic Broadcast) 是 Zookeeper 資料一致性的核心演算法,是 Zookeeper 實現分散式系統資料一致性。ZAB 協議專門為 Zookeeper 設計了一種支援崩潰恢復的原子廣播協議。

ZAB 協議的核心:所有事務請求(寫請求)必須由一個全域性唯一的 Leader 伺服器來協調處理 ,而餘下的其他伺服器則成為 Follower 伺服器。 Leader 伺服器負責將一個客戶端事務請求轉換成一個事務 proposal(提議),並將該 Proposal 分發給叢集中所有的 Follower 伺服器。之後 Leader 伺服器需要等待所有 Follower 伺服器的反饋,一旦超過半數的 Follower 伺服器進行了正確的反饋後,那麼 Leader 就會再次向所有的 Follower 伺服器分 發 Commit 訊息,要求其將前一個 proposal 進行提交。

ZAB 協議包括兩種基本的模式,分別是 崩潰恢復和訊息廣播

當整個服務框架在啟動過程中,或是當 Leader 伺服器出現網路中斷、崩潰退出與重啟等異常情況時, ZAB 協議就會進入恢復模式並選舉產生新的 Leader 伺服器。當選舉產生了新的 Leader 伺服器同時叢集中已經有過半的機器與該 Leader 伺服器完成了狀態同步之後,ZAB 協議就會退出恢復模式。

當叢集中已經有過半的 Follower 伺服器完成了和 Leader 伺服器的狀態同步,那麼整個服務框架就可以進入訊息廣播模式了。當一臺同樣遵守 ZAB 協議的伺服器啟動後加入到叢集中時,如果此時叢集中已經存在一個 Leader 伺服器在負責進行訊息廣播, 那麼新加入的伺服器就會自覺地進入資料恢復模式:找到 Leader 所在的伺服器,並與其進行資料同步,然後一起參與到訊息廣播流程中去。

下面重點講解崩潰回覆和訊息廣播的過程。

2.1 訊息廣播

ZAB 協議的訊息廣播過程使用的是一個原子廣播協議,類似於一個二階段提交過程。針對客戶端的事務請求, Leader 伺服器會為其生成對應的事務 Proposal ,並將其傳送給叢集中其餘所有的機器,然後再分別收集各自的選票,最後進行事務提交。

訊息廣播
  
在 ZAB 協議的二階段提交過程中,移除了中斷邏輯,所有的 Follower 伺服器要麼正常反饋 Leader 提出的事務 Proposal ,要麼就拋棄 Leader 伺服器。同時, ZAB 協議將二階段提交中的中斷邏輯移除意味著我們可以在過半的 Follower 伺服器已經反饋 Ack 之後就開始提交事務 Proposal 了,而不需要等待叢集中所有的 Follower 伺服器都反饋響應。這種簡化了的二階段提交模型無法處理 Leader 伺服器崩潰退出而帶來的資料不一致問題,此時採用崩潰恢復模式來解決這個問題。

在整個訊息廣播過程中, Leader 伺服器會為每個事務請求生成對應的 Proposal 來進行廣播,並且在廣播事務 Proposal 之前, Leader 伺服器會首先為這個事務 Proposal 分配一個全域性單調遞增的唯一事務ID (即 ZXID)。

Leader 伺服器會為每一個 Follower 伺服器都各自分配一個單獨的佇列,然後將需要廣播的事務 Proposal 依次放入這些佇列中去,並且根據 FIFO 策略進行訊息傳送。每一個 Follower 伺服器在接收到這個事務 Proposal 之後,都會首先將其以事務日誌的形式寫入到本地磁碟中去,並且在成功寫入後反饋給 Leader 伺服器一個 Ack 響應。當 Leader 伺服器接收到超過半數 Follower 的 Ack 響應後,就會廣播一個 Commit 訊息給所有的 Follower 伺服器以通知其進行事務提交,同時 Leader 自身也會完成對事務的提交。

2.2 崩潰恢復

Leader 伺服器出現崩潰,或者說由於網路原因導致 Leader 伺服器失去了與過半 Follower 的聯絡,那麼就會進入崩潰恢復模式。Leader 選舉演算法不僅僅需要讓 Leader 自己知道其自身已經被選舉為 Leader ,同時還需要讓叢集中的所有其他機器也能夠快速地感知到選舉產生的新的 Leader 伺服器。

ZAB 協議規定了如果一個事務 Proposal 在一臺機器上被處理成功,那麼應該在所有的機器上都被處理成功,哪怕機器出現故障崩潰。

下面介紹兩種崩潰恢復中的場景和 ZAB 協議需要保證的特性:

  1. ZAB 協議需要確保那些已經在 Leader 伺服器上提交的事務最終被所有伺服器都提交

    假設一個事務在 Leader 伺服器上被提交了,並且已經得到過半 Follower 伺服器的 Ack 反饋,但是在它將 Commit 訊息傳送給所有 Follower 機器之前, Leader 伺服器掛了,針對這種情況, ZAB 協議就需要確保該事務最終能夠在所有的伺服器上都被提交成功,否則將出現不一致。

  2. ZAB 協議需要確保丟棄那些只在 Leader 伺服器上被提出的事務

    假設初始的 Leader 伺服器 在提出了一個事務之後就崩潰退出了,導致叢集中的其他伺服器都沒有收到這個事務,當該伺服器恢復過來再次加入到叢集中的時候 ,ZAB協議需要確保丟棄這個事務。

針對以上兩點需求,ZAB 協議需要設計的選舉演算法應該滿足:確保提交已經被 Leader 提交的事務 Proposal,同時丟棄已經被跳過的事務 Proposal 。

如果讓 Leader 選舉演算法能夠保證新選舉出來的 Leader 伺服器擁有叢集中所有機器最高編號(即 ZXID 最大)的事務 Proposal,那麼就可以保證這個新選舉出來的 Leader 一定具有所有已經提交的提案。同時,如果讓具有最高編號事務 Proposal 的機器來成為 Leader,就可以省去 Leader 伺服器檢查 Proposal 的提交和丟棄工作的這一步操作。

2.3 資料同步

Leader 伺服器會為每一個 Follower 伺服器都準備一個佇列,並將那些沒有被各 Follower 伺服器同步的事務以 Proposal 訊息的形式逐個傳送給 Follower 伺服器,並在每一個 Proposal 訊息後面緊接著再發送一個 Commit 訊息,以表示該事務已經被提交。等到 Follower 伺服器將所有其尚未同步的事務 Proposal 都從 Leader 伺服器上同步過來併成功應用到本地資料庫中後, Leader 伺服器就會將該 Follower 伺服器加入到真正的可用 Follower 列表中,並開始之後的其他流程。

下面來看 ZAB 協議是如何處理那些需要被丟棄的事務 Proposal 的。在 ZAB 協議的事務編號 ZXID 設計中, ZXID 是一個 64 位的數字,低 32 位可以看作是一個簡單的單調遞增的計數器,針對客戶端的每一個事務請求, Leader 伺服器在產生一個新的事務 Proposal 的時候,都會對該計數器進行加 1 操作;高 32 位代表了 Leader 週期 epoch 的編號,每當選舉產生一個新的 Leader 伺服器,就會從這個 Leader 伺服器上取出其本地日誌中最大事務 Proposal 的 ZXID ,並從該 ZXID 中解析出對應的 epoch 值,然後再對其進行加 1 操作,之後就會以此編號作為新的 epoch, 並將低 32 位置 0 來開始生成新的 ZXID 。

基於這樣的策略,當一個包含了上一個 Leader 週期中尚未提交過的事務 Proposal 的伺服器啟動加入到叢集中,發現此時叢集中已經存在 Leader,將自身以 Follower 角色連線上 Leader 伺服器之後,Leader 伺服器會根據自己伺服器上最後被提交的 Proposal 來和 Follower 伺服器的 Proposal 進行比對,發現 Follower 中有上一個 Leader 週期的事務 Proposal 時,Leader 會要求 Follower 進行一個回退操作-回退到一個確實已經被叢集中過半機器提交的最新的事務 Proposal 。

2.4 ZAB 協議原理

ZAB 主要包括訊息廣播和崩潰恢復兩個過程,進一步可以分為三個階段,分別是發現(Discovery)、同步(Synchronization)、廣播(Broadcast)階段。ZAB 的每一個分散式程序會迴圈執行這三個階段,稱為主程序週期。

  1. 發現
    即要求 zookeeper 叢集必須選擇出一個 Leader 程序,同時 Leader 會維護一個 Follower 可用列表。

  2. 同步
    Leader 要負責將本身的資料與 Follower 完成同步,做到多副本儲存。這樣也是體現了 CAP 中高可用和分割槽容錯。Follower 將佇列中未處理完的請求消費完成後,寫入本地事物日誌中。

  3. 廣播
    Leader 可以接受客戶端新的 proposal 請求,將新的 proposal 請求廣播給所有的 Follower。

在正常執行過程中,ZAB 協議會一直運行於階段三來反覆進行訊息廣播流程,如果出現崩潰或其他原因導致 Leader 缺失,那麼此時 ZAB 協議會再次進入發現階段,選舉新的 Leader。

每個程序都有可能處於如下三種狀態之一:

  • LOOKING:Leader 選舉階段。
  • FOLLOWING:Follower 伺服器和 Leader 伺服器保持同步狀態。
  • LEADING:Leader 伺服器作為主程序領導狀態。

所有程序初始狀態都是 LOOKING 狀態,此時不存在 Leader,此時,程序會試圖選舉出一個新的 Leader,之後,如果程序發現已經選舉出新的 Leader 了,那麼它就會切換到 FOLLOWING 狀態,並開始和 Leader 保持同步,處於 FOLLOWING 狀態的程序稱為 Follower,LEADING 狀態的程序稱為 Leader,當 Leader 崩潰或放棄領導地位時,其餘的 Follower 程序就會轉換到 LOOKING 狀態開始新一輪的 Leader 選舉。

一個 Follower 只能和一個 Leader 保持同步,Leader 程序和所有與所有的 Follower 程序之間都通過心跳檢測機制來感知彼此的情況。若 Leader 能夠在超時時間內正常收到心跳檢測,那麼 Follower 就會一直與該 Leader 保持連線,而如果在指定時間內 Leader 無法從過半的 Follower 程序那裡接收到心跳檢測,或者 TCP 連線斷開,那麼 Leader 會放棄當前週期的領導,比你轉換到 LOOKING 狀態,其他的 Follower 也會選擇放棄這個 Leader,同時轉換到 LOOKING 狀態,之後會進行新一輪的 Leader 選舉,並在選舉產生新的 Leader 之後開始新的一輪主程序週期。


每天用心記錄一點點。內容也許不重要,但習慣很重要!