Zookeeper——一致性協議:Zab協議

Reference: https://www.jianshu.com/p/2bceacd60b8a算法

  • 什麼是Zab協議
  • Zab 協議的做用
  • Zab 協議原理
  • Zab 協議核心
  • Zab 協議內容
  • 原子廣播
  • 崩潰恢復
  • 如何保證數據一致性
  • Zab 協議如何數據同步
  • 如何處理須要丟棄的 Proposal
  • Zab 協議實現原理
  • 選主過程

什麼是Zab協議?

Zab協議 的全稱是 Zookeeper Atomic Broadcast (Zookeeper原子廣播)。
Zookeeper 是經過 Zab 協議來保證分佈式事務的最終一致性服務器

  1. Zab協議是爲分佈式協調服務Zookeeper專門設計的一種 支持崩潰恢復原子廣播協議 ,是Zookeeper保證數據一致性的核心算法。Zab借鑑了Paxos算法,但又不像Paxos那樣,是一種通用的分佈式一致性算法。它是特別爲Zookeeper設計的支持崩潰恢復的原子廣播協議網絡

  2. 在Zookeeper中主要依賴Zab協議來實現數據一致性,基於該協議,zk實現了一種主備模型(即Leader和Follower模型)的系統架構來保證集羣中各個副本之間數據的一致性。
    這裏的主備系統架構模型,就是指只有一臺客戶端(Leader)負責處理外部的寫事務請求,而後Leader客戶端將數據同步到其餘Follower節點。架構

Zookeeper 客戶端會隨機的連接到 zookeeper 集羣中的一個節點,若是是讀請求,就直接從當前節點中讀取數據;若是是寫請求,那麼節點就會向 Leader 提交事務,Leader 接收到事務提交,會廣播該事務,只要超過半數節點寫入成功,該事務就會被提交。app

Zab 協議的特性
1)Zab 協議須要確保那些已經在 Leader 服務器上提交(Commit)的事務最終被全部的服務器提交
2)Zab 協議須要確保丟棄那些只在 Leader 上被提出而沒有被提交的事務異步

 
模型圖

 

Zab 協議實現的做用

1)使用一個單一的主進程(Leader)來接收並處理客戶端的事務請求(也就是寫請求),並採用了Zab的原子廣播協議,將服務器數據的狀態變動以 事務proposal (事務提議)的形式廣播到全部的副本(Follower)進程上去。
分佈式

2)保證一個全局的變動序列被順序引用
Zookeeper是一個樹形結構,不少操做都要先檢查才能肯定是否能夠執行,好比P1的事務t1多是建立節點"/a",t2多是建立節點"/a/bb",只有先建立了父節點"/a",才能建立子節點"/a/b"。性能

爲了保證這一點,Zab要保證同一個Leader發起的事務要按順序被apply,同時還要保證只有先前Leader的事務被apply以後,新選舉出來的Leader才能再次發起事務。
設計

3)當主進程出現異常的時候,整個zk集羣依舊能正常工做日誌


 

Zab協議原理

Zab協議要求每一個 Leader 都要經歷三個階段:發現,同步,廣播

  • 發現:要求zookeeper集羣必須選舉出一個 Leader 進程,同時 Leader 會維護一個 Follower 可用客戶端列表。未來客戶端能夠和這些 Follower節點進行通訊。

  • 同步:Leader 要負責將自己的數據與 Follower 完成同步,作到多副本存儲。這樣也是提現了CAP中的高可用和分區容錯。Follower將隊列中未處理完的請求消費完成後,寫入本地事務日誌中。

  • 廣播:Leader 能夠接受客戶端新的事務Proposal請求,將新的Proposal請求廣播給全部的 Follower。


 

Zab協議核心

Zab協議的核心:定義了事務請求的處理方式

1)全部的事務請求必須由一個全局惟一的服務器來協調處理,這樣的服務器被叫作 Leader服務器。其餘剩餘的服務器則是 Follower服務器

2)Leader服務器 負責將一個客戶端事務請求,轉換成一個 事務Proposal,並將該 Proposal 分發給集羣中全部的 Follower 服務器,也就是向全部 Follower 節點發送數據廣播請求(或數據複製)

3)分發以後Leader服務器須要等待全部Follower服務器的反饋(Ack請求),在Zab協議中,只要超過半數的Follower服務器進行了正確的反饋後(也就是收到半數以上的Follower的Ack請求),那麼 Leader 就會再次向全部的 Follower服務器發送 Commit 消息,要求其將上一個 事務proposal 進行提交。

 
事務請求處理

 

Zab協議內容

Zab 協議包括兩種基本的模式:崩潰恢復消息廣播

協議過程

當整個集羣啓動過程當中,或者當 Leader 服務器出現網絡中弄斷、崩潰退出或重啓等異常時,Zab協議就會 進入崩潰恢復模式,選舉產生新的Leader。

當選舉產生了新的 Leader,同時集羣中有過半的機器與該 Leader 服務器完成了狀態同步(即數據同步)以後,Zab協議就會退出崩潰恢復模式,進入消息廣播模式

這時,若是有一臺遵照Zab協議的服務器加入集羣,由於此時集羣中已經存在一個Leader服務器在廣播消息,那麼該新加入的服務器自動進入恢復模式:找到Leader服務器,而且完成數據同步。同步完成後,做爲新的Follower一塊兒參與到消息廣播流程中。

協議狀態切換

當Leader出現崩潰退出或者機器重啓,亦或是集羣中不存在超過半數的服務器與Leader保存正常通訊,Zab就會再一次進入崩潰恢復,發起新一輪Leader選舉並實現數據同步。同步完成後又會進入消息廣播模式,接收事務請求。

保證消息有序

在整個消息廣播中,Leader會將每個事務請求轉換成對應的 proposal 來進行廣播,而且在廣播 事務Proposal 以前,Leader服務器會首先爲這個事務Proposal分配一個全局單遞增的惟一ID,稱之爲事務ID(即zxid),因爲Zab協議須要保證每個消息的嚴格的順序關係,所以必須將每個proposal按照其zxid的前後順序進行排序和處理。


 

消息廣播

1)在zookeeper集羣中,數據副本的傳遞策略就是採用消息廣播模式。zookeeper中農數據副本的同步方式與二段提交類似,可是卻又不一樣。二段提交要求協調者必須等到全部的參與者所有反饋ACK確認消息後,再發送commit消息。要求全部的參與者要麼所有成功,要麼所有失敗。二段提交會產生嚴重的阻塞問題。

2)Zab協議中 Leader 等待 Follower 的ACK反饋消息是指「只要半數以上的Follower成功反饋便可,不須要收到所有Follower反饋」

 

 
消息廣播流程圖


 

消息廣播具體步驟

1)客戶端發起一個寫操做請求。

2)Leader 服務器將客戶端的請求轉化爲事務 Proposal 提案,同時爲每一個 Proposal 分配一個全局的ID,即zxid。

3)Leader 服務器爲每一個 Follower 服務器分配一個單獨的隊列,而後將須要廣播的 Proposal 依次放到隊列中取,而且根據 FIFO 策略進行消息發送。

4)Follower 接收到 Proposal 後,會首先將其以事務日誌的方式寫入本地磁盤中,寫入成功後向 Leader 反饋一個 Ack 響應消息。

5)Leader 接收到超過半數以上 Follower 的 Ack 響應消息後,即認爲消息發送成功,能夠發送 commit 消息。

6)Leader 向全部 Follower 廣播 commit 消息,同時自身也會完成事務提交。Follower 接收到 commit 消息後,會將上一條事務提交。

zookeeper 採用 Zab 協議的核心,就是隻要有一臺服務器提交了 Proposal,就要確保全部的服務器最終都能正確提交 Proposal。這也是 CAP/BASE 實現最終一致性的一個體現。

Leader 服務器與每個 Follower 服務器之間都維護了一個單獨的 FIFO 消息隊列進行收發消息,使用隊列消息能夠作到異步解耦。 Leader 和 Follower 之間只須要往隊列中發消息便可。若是使用同步的方式會引發阻塞,性能要降低不少。


 

崩潰恢復

一旦 Leader 服務器出現崩潰或者因爲網絡緣由致使 Leader 服務器失去了與過半 Follower 的聯繫,那麼就會進入崩潰恢復模式。

在 Zab 協議中,爲了保證程序的正確運行,整個恢復過程結束後須要選舉出一個新的 Leader 服務器。所以 Zab 協議須要一個高效且可靠的 Leader 選舉算法,從而確保可以快速選舉出新的 Leader 。

Leader 選舉算法不只僅須要讓 Leader 本身知道本身已經被選舉爲 Leader ,同時還須要讓集羣中的全部其餘機器也可以快速感知到選舉產生的新 Leader 服務器。

崩潰恢復主要包括兩部分:Leader選舉數據恢復

 

Zab 協議如何保證數據一致性

假設兩種異常狀況:
一、一個事務在 Leader 上提交了,而且過半的 Folower 都響應 Ack 了,可是 Leader 在 Commit 消息發出以前掛了。
二、假設一個事務在 Leader 提出以後,Leader 掛了。

要確保若是發生上述兩種狀況,數據還能保持一致性,那麼 Zab 協議選舉算法必須知足如下要求:

Zab 協議崩潰恢復要求知足如下兩個要求
1)確保已經被 Leader 提交的 Proposal 必須最終被全部的 Follower 服務器提交
2)確保丟棄已經被 Leader 提出的可是沒有被提交的 Proposal

根據上述要求
Zab協議須要保證選舉出來的Leader須要知足如下條件:
1)新選舉出來的 Leader 不能包含未提交的 Proposal
即新選舉的 Leader 必須都是已經提交了 Proposal 的 Follower 服務器節點。
2)新選舉的 Leader 節點中含有最大的 zxid
這樣作的好處是能夠避免 Leader 服務器檢查 Proposal 的提交和丟棄工做。

Zab 如何數據同步

1)完成 Leader 選舉後(新的 Leader 具備最高的zxid),在正式開始工做以前(接收事務請求,而後提出新的 Proposal),Leader 服務器會首先確認事務日誌中的全部的 Proposal 是否已經被集羣中過半的服務器 Commit。

2)Leader 服務器須要確保全部的 Follower 服務器可以接收到每一條事務的 Proposal ,而且能將全部已經提交的事務 Proposal 應用到內存數據中。等到 Follower 將全部還沒有同步的事務 Proposal 都從 Leader 服務器上同步過啦而且應用到內存數據中之後,Leader 纔會把該 Follower 加入到真正可用的 Follower 列表中。

Zab 數據同步過程當中,如何處理須要丟棄的 Proposal

在 Zab 的事務編號 zxid 設計中,zxid是一個64位的數字。

其中低32位能夠當作一個簡單的單增計數器,針對客戶端每個事務請求,Leader 在產生新的 Proposal 事務時,都會對該計數器加1。而高32位則表明了 Leader 週期的 epoch 編號。

epoch 編號能夠理解爲當前集羣所處的年代,或者週期。每次Leader變動以後都會在 epoch 的基礎上加1,這樣舊的 Leader 崩潰恢復以後,其餘Follower 也不會聽它的了,由於 Follower 只服從epoch最高的 Leader 命令。

每當選舉產生一個新的 Leader ,就會從這個 Leader 服務器上取出本地事務日誌充最大編號 Proposal 的 zxid,並從 zxid 中解析獲得對應的 epoch 編號,而後再對其加1,以後該編號就做爲新的 epoch 值,並將低32位數字歸零,由0開始從新生成zxid。

Zab 協議經過 epoch 編號來區分 Leader 變化週期,可以有效避免不一樣的 Leader 錯誤的使用了相同的 zxid 編號提出了不同的 Proposal 的異常狀況。

基於以上策略
當一個包含了上一個 Leader 週期中還沒有提交過的事務 Proposal 的服務器啓動時,當這臺機器加入集羣中,以 Follower 角色連上 Leader 服務器後,Leader 服務器會根據本身服務器上最後提交的 Proposal 來和 Follower 服務器的 Proposal 進行比對,比對的結果確定是 Leader 要求 Follower 進行一個回退操做,回退到一個確實已經被集羣中過半機器 Commit 的最新 Proposal


 

實現原理

Zab 節點有三種狀態

  • Following:當前節點是跟隨者,服從 Leader 節點的命令。
  • Leading:當前節點是 Leader,負責協調事務。
  • Election/Looking:節點處於選舉狀態,正在尋找 Leader。

代碼實現中,多了一種狀態:Observing 狀態
這是 Zookeeper 引入 Observer 以後加入的,Observer 不參與選舉,是隻讀節點,跟 Zab 協議沒有關係。

節點的持久狀態

  • history:當前節點接收到事務 Proposal 的Log
  • acceptedEpoch:Follower 已經接受的 Leader 更改 epoch 的 newEpoch 提議。
  • currentEpoch:當前所處的 Leader 年代
  • lastZxid:history 中最近接收到的Proposal 的 zxid(最大zxid)

Zab 的四個階段

一、選舉階段(Leader Election)
節點在一開始都處於選舉節點,只要有一個節點獲得超過半數節點的票數,它就能夠當選準 Leader,只有到達第三個階段(也就是同步階段),這個準 Leader 纔會成爲真正的 Leader。

Zookeeper 規定全部有效的投票都必須在同一個 輪次 中,每一個服務器在開始新一輪投票時,都會對本身維護的 logicalClock 進行自增操做

每一個服務器在廣播本身的選票前,會將本身的投票箱(recvset)清空。該投票箱記錄了所受到的選票。
例如:Server_2 投票給 Server_3,Server_3 投票給 Server_1,則Server_1的投票箱爲(2,3)、(3,1)、(1,1)。(每一個服務器都會默認給本身投票)

前一個數字表示投票者,後一個數字表示被選舉者。票箱中只會記錄每個投票者的最後一次投票記錄,若是投票者更新本身的選票,則其餘服務器收到該新選票後會在本身的票箱中更新該服務器的選票。

這一階段的目的就是爲了選出一個準 Leader ,而後進入下一個階段。
協議並無規定詳細的選舉算法,後面會提到實現中使用的 Fast Leader Election。

 
選舉流程


 

二、發現階段(Descovery)
在這個階段,Followers 和上一輪選舉出的準 Leader 進行通訊,同步 Followers 最近接收的事務 Proposal 。
一個 Follower 只會鏈接一個 Leader,若是一個 Follower 節點認爲另外一個 Follower 節點,則會在嘗試鏈接時被拒絕。被拒絕以後,該節點就會進入 Leader Election階段。

這個階段的主要目的是發現當前大多數節點接收的最新 Proposal,而且準 Leader 生成新的 epoch ,讓 Followers 接收,更新它們的 acceptedEpoch

 
發現流程


 

三、同步階段(Synchronization)
同步階段主要是利用 Leader 前一階段得到的最新 Proposal 歷史,同步集羣中全部的副本
只有當 quorum(超過半數的節點) 都同步完成,準 Leader 纔會成爲真正的 Leader。Follower 只會接收 zxid 比本身 lastZxid 大的 Proposal。

 
同步流程


 

四、廣播階段(Broadcast)
到了這個階段,Zookeeper 集羣才能正式對外提供事務服務,而且 Leader 能夠進行消息廣播。同時,若是有新的節點加入,還須要對新節點進行同步。
須要注意的是,Zab 提交事務並不像 2PC 同樣須要所有 Follower 都 Ack,只須要獲得 quorum(超過半數的節點)的Ack 就能夠。

 
廣播流程

 


 

協議實現

協議的 Java 版本實現跟上面的定義略有不一樣,選舉階段使用的是 Fast Leader Election(FLE),它包含了步驟1的發現指責。由於FLE會選舉擁有最新提議的歷史節點做爲 Leader,這樣就省去了發現最新提議的步驟。

實際的實現將發現和同步階段合併爲 Recovery Phase(恢復階段),因此,Zab 的實現實際上有三個階段。

Zab協議三個階段:

1)選舉(Fast Leader Election)
2)恢復(Recovery Phase)
3)廣播(Broadcast Phase)

Fast Leader Election(快速選舉)
前面提到的 FLE 會選舉擁有最新Proposal history (lastZxid最大)的節點做爲 Leader,這樣就省去了發現最新提議的步驟。這是基於擁有最新提議的節點也擁有最新的提交記錄

  • 成爲 Leader 的條件:
    1)選 epoch 最大的
    2)若 epoch 相等,選 zxid 最大的
    3)若 epoch 和 zxid 相等,選擇 server_id 最大的(zoo.cfg中的myid)

節點在選舉開始時,都默認投票給本身,當接收其餘節點的選票時,會根據上面的 Leader條件 判斷而且更改本身的選票,而後從新發送選票給其餘節點。當有一個節點的得票超過半數,該節點會設置本身的狀態爲 Leading ,其餘節點會設置本身的狀態爲 Following

 

 
選舉過程


 

Recovery Phase(恢復階段)
這一階段 Follower 發送他們的 lastZxid 給 Leader,Leader 根據 lastZxid 決定如何同步數據。這裏的實現跟前面的 Phase 2 有所不一樣:Follower 收到 TRUNC 指令會終止 L.lastCommitedZxid 以後的 Proposal ,收到 DIFF 指令會接收新的 Proposal。

history.lastCommitedZxid:最近被提交的 Proposal zxid
history.oldThreshold:被認爲已經太舊的已經提交的 Proposal zxid


 
恢復階段
做者:_Zy 連接:https://www.jianshu.com/p/2bceacd60b8a 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索