ZooKeeper 如何保證數據一致性?


在分布式場景中,ZooKeeper 的應用非常廣泛,比如數據發布和訂閱、命名服務、配置中心、注冊中心、分布式鎖等。

在分布式場景中,ZooKeeper 的應用非常廣泛,比如數據發布和訂閱、命名服務、配置中心、注冊中心、分布式鎖等。

ZooKeeper 提供了一個類似於 Linux 文件系統的數據模型,和基於 Watcher 機制的分布式事件通知,這些特性都依賴 ZooKeeper 的高容錯數據一致性協議。

那么問題來了,在分布式場景下,ZooKeeper 是如何實現數據一致性的呢?

Zab 一致性協議

ZooKeeper 是通過 Zab 協議來保證分布式事務的最終一致性。Zab(ZooKeeper Atomic Broadcast,ZooKeeper 原子廣播協議)支持崩潰恢復,基於該協議,ZooKeeper 實現了一種主備模式的系統架構來保持集群中各個副本之間數據一致性。

系統架構可以參考下面這張圖:

在 ZooKeeper 集群中,所有客戶端的請求都是寫入到 Leader 進程中的,然后,由 Leader 同步到其他節點,稱為 Follower。在集群數據同步的過程中,如果出現 Follower 節點崩潰或者 Leader 進程奔潰時,都會通過 Zab 協議來保證數據一致性。

Zab 協議的具體實現可以分為以下兩部分:

  • 消息廣播階段

Leader 節點接受事務提交,並且將新的 Proposal 請求廣播給 Follower 節點,收集各個節點的反饋,決定是否進行 Commit,在這個過程中,也會使用上一課時提到的 Quroum 選舉機制。

  • 崩潰恢復階段

如果在同步過程中出現 Leader 節點宕機,會進入崩潰恢復階段,重新進行 Leader 選舉,崩潰恢復階段還包含數據同步操作,同步集群中最新的數據,保持集群的數據一致性。

整個 ZooKeeper 集群的一致性保證就是在上面兩個狀態之前切換,當 Leader 服務正常時,就是正常的消息廣播模式;當 Leader 不可用時,則進入崩潰恢復模式,崩潰恢復階段會進行數據同步,完成以后,重新進入消息廣播階段。

Zab 協議中的 Zxid

Zxid 在 ZooKeeper 的一致性流程中非常重要,在詳細分析 Zab 協議之前,先來看下 Zxid 的概念。

Zxid 是 Zab 協議的一個事務編號,Zxid 是一個 64 位的數字,其中低 32 位是一個簡單的單調遞增計數器,針對客戶端每一個事務請求,計數器加 1;而高 32 位則代表 Leader 周期年代的編號。

這里 Leader 周期的英文是 epoch,可以理解為當前集群所處的年代或者周期,對比另外一個一致性算法 Raft 中的 Term 概念。在 Raft 中,每一個任期的開始都是一次選舉,Raft 算法保證在給定的一個任期最多只有一個領導人。

 

Zab 協議的實現也類似,每當有一個新的 Leader 選舉出現時,就會從這個 Leader 服務器上取出其本地日志中最大事務的 Zxid,並從中讀取 epoch 值,然后加 1,以此作為新的周期 ID。總結一下,高 32 位代表了每代 Leader 的唯一性,低 32 位則代表了每代 Leader 中事務的唯一性。

Zab 流程分析

Zab 的具體流程可以拆分為消息廣播、崩潰恢復和數據同步三個過程,下面我們分別進行分析。

 

消息廣播

在 ZooKeeper 中所有的事務請求都由 Leader 節點來處理,其他服務器為 Follower,Leader 將客戶端的事務請求轉換為事務 Proposal,並且將 Proposal 分發給集群中其他所有的 Follower。

完成廣播之后,Leader 等待 Follwer 反饋,當有過半數的 Follower 反饋信息后,Leader 將再次向集群內 Follower 廣播 Commit 信息,Commit 信息就是確認將之前的 Proposal 提交

這里的 Commit 可以對比 SQL 中的 COMMIT 操作來理解,MySQL 默認操作模式是 autocommit 自動提交模式,如果你顯式地開始一個事務,在每次變更之后都要通過 COMMIT 語句來確認,將更改提交到數據庫中。

Leader 節點的寫入也是一個兩步操作,第一步是廣播事務操作,第二步是廣播提交操作,其中過半數指的是反饋的節點數 >=N/2+1,N 是全部的 Follower 節點數量。

消息廣播的過程描述可以參考下圖:

  • 客戶端的寫請求進來之后,Leader 會將寫請求包裝成 Proposal 事務,並添加一個遞增事務 ID,也就是 Zxid,Zxid 是單調遞增的,以保證每個消息的先后順序;

  • 廣播這個 Proposal 事務,Leader 節點和 Follower 節點是解耦的,通信都會經過一個先進先出的消息隊列,Leader 會為每一個 Follower 服務器分配一個單獨的 FIFO 隊列,然后把 Proposal 放到隊列中;

  • Follower 節點收到對應的 Proposal 之后會把它持久到磁盤上,當完全寫入之后,發一個 ACK 給 Leader;

  • 當 Leader 收到超過半數 Follower 機器的 ack 之后,會提交本地機器上的事務,同時開始廣播 commit, Follower 收到 commit 之后,完成各自的事務提交。

分析完消息廣播,我們再來看一下崩潰恢復。

崩潰恢復

消息廣播通過 Quroum 機制,解決了 Follower 節點宕機的情況,但是如果在廣播過程中 Leader 節點崩潰呢?

 

這就需要 Zab 協議支持的崩潰恢復,崩潰恢復可以保證在 Leader 進程崩潰的時候可以重新選出 Leader,並且保證數據的完整性。

 

崩潰恢復和集群啟動時的選舉過程是一致的,也就是說,下面的幾種情況都會進入崩潰恢復階段:

  • 初始化集群,剛剛啟動的時候

  • Leader 崩潰,因為故障宕機

  • Leader 失去了半數的機器支持,與集群中超過一半的節點斷連

 

崩潰恢復模式將會開啟新的一輪選舉,選舉產生的 Leader 會與過半的 Follower 進行同步,使數據一致,當與過半的機器同步完成后,就退出恢復模式, 然后進入消息廣播模式。

 

Zab 中的節點有三種狀態,伴隨着的 Zab 不同階段的轉換,節點狀態也在變化:

 

 

我們通過一個模擬的例子,來了解崩潰恢復階段,也就是選舉的流程。

 

假設正在運行的集群有五台 Follower 服務器,編號分別是 Server1、Server2、Server3、Server4、Server5,當前 Leader 是 Server2,若某一時刻 Leader 掛了,此時便開始 Leader 選舉。

 

選舉過程如下:

 

1.各個節點變更狀態,變更為 Looking

ZooKeeper 中除了 Leader 和 Follower,還有 Observer 節點,Observer 不參與選舉,Leader 掛后,余下的 Follower 節點都會將自己的狀態變更為 Looking,然后開始進入 Leader 選舉過程。

 

2.各個 Server 節點都會發出一個投票,參與選舉

在第一次投票中,所有的 Server 都會投自己,然后各自將投票發送給集群中所有機器,在運行期間,每個服務器上的 Zxid 大概率不同。

 

3.集群接收來自各個服務器的投票,開始處理投票和選舉

處理投票的過程就是對比 Zxid 的過程,假定 Server3 的 Zxid 最大,Server1 判斷 Server3 可以成為 Leader,那么 Server1 就投票給 Server3,判斷的依據如下:

首先選舉 epoch 最大的

如果 epoch 相等,則選 zxid 最大的

若 epoch 和 zxid 都相等,則選擇 server id 最大的,就是配置 zoo.cfg 中的 myid

 

在選舉過程中,如果有節點獲得超過半數的投票數,則會成為 Leader 節點,反之則重新投票選舉。

 

 

4.選舉成功,改變服務器的狀態,參考上面這張圖的狀態變更

數據同步

崩潰恢復完成選舉以后,接下來的工作就是數據同步,在選舉過程中,通過投票已經確認 Leader 服務器是最大Zxid 的節點,同步階段就是利用 Leader 前一階段獲得的最新Proposal歷史,同步集群中所有的副本。

 

上面分析了 Zab 協議的具體流程,接下來我們對比一下 Zab 協議和 Paxos 算法。

Zab 與 Paxos 算法的聯系與區別

Paxos 的思想在很多分布式組件中都可以看到,Zab 協議可以認為是基於 Paxos 算法實現的,先來看下兩者之間的聯系:

  • 都存在一個 Leader 進程的角色,負責協調多個 Follower 進程的運行

  • 都應用 Quroum 機制,Leader 進程都會等待超過半數的 Follower 做出正確的反饋后,才會將一個提案進行提交

  • 在 Zab 協議中,Zxid 中通過 epoch 來代表當前 Leader 周期,在 Paxos 算法中,同樣存在這樣一個標識,叫做 Ballot Number

 

兩者之間的區別是,Paxos 是理論,Zab 是實踐,Paxos 是論文性質的,目的是設計一種通用的分布式一致性算法,而 Zab 協議應用在 ZooKeeper 中,是一個特別設計的崩潰可恢復的原子消息廣播算法。

 

Zab 協議增加了崩潰恢復的功能,當 Leader 服務器不可用,或者已經半數以上節點失去聯系時,ZooKeeper 會進入恢復模式選舉新的 Leader 服務器,使集群達到一個一致的狀態。

總結

這一課時的內容分享了 ZooKeeper 一致性實現,包括 Zab 協議中的 Zxid 結構,Zab 協議具體的流程實現,以及 Zab 和原生 Paxos 算法的區別和聯系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM