面試官問:ZooKeeper是強一致的嗎?怎麼實現的?

Zookeeper通過ZAB保證分佈式事務的最終一致性。

ZAB全稱Zookeeper Atomic Broadcast(ZAB,Zookeeper原子消息廣播協議)

1.ZAB是一種專門爲Zookeeper設計的一種支持 崩潰恢復 的 原子廣播協議 ,是Zookeeper保證數據一致性的核心算法。ZAB借鑑了Paxos算法,但它不是通用的一致性算法,是特別爲Zookeeper設計的。

2.基於ZAB協議,Zookeeper實現了⼀種主備模式的系統架構來保持集羣中各副本之間的數據的⼀致性,表現形式就是使⽤⼀個單⼀的主進程(Leader服務器)來接收並處理客戶端的所有事務請求(寫請求),並採⽤ZAB的原⼦⼴播協議,將服務器數據的狀態變更爲事務 Proposal的形式⼴播到所有的Follower進程中。

問題提出

  • 主從架構下,leader 崩潰,數據一致性怎麼保證?
  • 選舉 leader 的時候,整個集羣無法處理寫請求的,如何快速進行 leader 選舉?

ZAB過程

ZAB協議的核⼼是 定義了對於那些會改變Zookeeper服務器數據狀態的事務請求的處理⽅式
在這裏插入圖片描述
所有事務必須由一個 全局唯一的服務器來協調處理 ,這樣的服務器被稱爲Leader服務器,餘下的服務器則稱爲Follower服務器

1.Leader服務器負責將一個客戶端事務請求轉化爲一個事務Proposal(提案),並將該Proposal分發給集羣中所有的Follower服務器

2.Leader服務器等待所有Follower服務器的反饋,一旦超過半數的Follower服務器進行了正確的反饋後,Leader就會向所有的Follower服務器發送Commit消息,要求將前一個Proposal進行提交。

ZAB協議內容簡介

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

消息廣播

當集羣中有過半的Follower服務器完成了和Leader服務器的狀態同步,那麼整個服務框架就可以進入 消息廣播模式 。

當一臺遵守ZAB協議的服務器啓動後加入到集羣中,如果此時集羣中已經存在一個Leader服務器在負責進行消息廣播,那麼加入的服務器會自覺的進入 數據恢復模式:找到Leader 所在的服務器,並與其進⾏數據同步,數據同步完成後參與到消息⼴播流程中。

ZAB協議的消息廣播使用原子廣播協議, 類似一個二階段提交的過程 ,但又有所不同。

1.二階段提交中,需要所有參與者反饋ACK後再發送Commit請求。要求所有參與者要麼成功,要麼失敗。這樣會產生嚴重的阻塞問題;

2.ZAB協議中,Leader等待半數以上的Follower成功反饋ACK即可,不需要收到全部的Follower反饋ACK。

消息廣播過程:

1.客戶端發起寫請求

2.Leader將客戶端請求信息轉化爲事務Proposal,同時爲每個Proposal分配一個事務ID(Zxid)

3.Leader爲每個Follower單獨分配一個FIFO的隊列,將需要廣播的Proposal依次放入到隊列中

4.Follower接收到Proposal後,首先將其以事務日誌的方式寫入到本地磁盤中,寫入成功後給Leader反饋一個ACK響應

5.Leader接收到半數以上Follower的ACK響應後,即認爲消息發送成功,可以發送Commit消息

6.Leader向所有Follower廣播Commit消息,同時自身也會完成事務提交。Follower接收到Commit消息後也會完成事務的提交
在這裏插入圖片描述
崩潰恢復

在整個服務框架啓動過程中,如果Leader服務器出現網絡中斷、崩潰退出或重啓等異常情況,ZAB協議就會進入崩潰恢復模式。同時選舉出新的Leader服務器。

當選舉產生了新的Leader服務器,同時集羣中已經有過半的機器與該Leader服務器完成了狀態同步(數據同步)之後,ZAB協議會退出恢復模式。

1.在ZAB協議中,爲了保證程序的正確運⾏,整個恢復過程結束後需要選舉出⼀個新的Leader 服務器。

2.Leader選舉算法不僅僅需要讓Leader⾃身知道已經被選舉爲Leader,同時還需要讓集羣中的所有其他機器也能夠快速地感知到選舉產⽣出來的新Leader服務器。

ZAB保證數據一致性

ZAB協議規定了 如果⼀個事務Proposal在⼀臺機器上被處理成功,那麼應該在所有的機器上都被處理成功,哪怕機器出現故障崩潰。 針對這些情況ZAB協議需要保證以下條件:

  • 已經在Leader服務器上提交的事務最終被所有服務器都提交。
    假設⼀個事務在 Leader 服務器上被提交了,並且已經得到過半 Folower 服務器的Ack反饋,但是在它 將Commit消息發送給所有Follower機器之前,Leader服務器掛了

  • 丟棄只在Leader服務器上被提出(未提交)的事務。
    假設初始的 Leader 服務器 Server1 在提出了⼀個事務Proposal3 之後就崩潰退出 了,從⽽導致集羣中的其他服務器都沒有收到這個事務Proposal3。於是,當 Server1 恢復過來再次加 ⼊到集羣中的時候,ZAB 協議需要確保丟棄Proposal3這個事務。

綜上所述,ZAB的選舉出來的Leader必須滿足以下條件:

能夠確保提交已經被 Leader 提交的事務 Proposal,同時丟棄已經被跳過的事務 Proposal。即:

1.新選舉出來的 Leader 不能包含未提交的 Proposal。

2.新選舉的 Leader 節點中含有最大的 zxid 。

ZAB如何數據同步

所有正常運行的服務器要麼成爲Leader,要麼成爲Follower並和Leader保持同步。

1.完成Leader選舉(新的 Leader 具有最高的zxid)之後,在正式開始⼯作(接收客戶端請求)之前,Leader服務器會⾸先確認事務⽇志中的所有Proposal是否都已經被集羣中過半的機器提交了,即 是否完成數據同步 。

2.Leader服務器需要確保所有的Follower服務器能夠接收到每⼀條事務Proposal,並且能夠正確地將所有已經提交了的事務Proposal應⽤到內存數據中。等到 Follower服務器將所有其尚未同步的事務 Proposal 都從 Leader 服務器上同步過來併成功應⽤到本地數據庫中後,Leader服務器就會將該Follower服務器加⼊到真正的可⽤Follower列表中,並開始之後的其他流程。

ZAB運行時狀態#

ZAB協議設計中,每個進程都有可能處於如下三種狀態之一:

  • LOOKING:Leader選舉狀態,正在尋找Leader
  • FOLLOWING:當前節點是Follower。與Leader服務器保持同步狀態
  • LEADING:當前節點是Leader,作爲主進程領導狀態。

ZAB狀態的切換

啓動時的狀態轉換
1.所有進程的初始狀態都是LOOKING狀態,此時不存在Leader。

2.接下來,進程會試圖選舉出來一個新的Leader,Leader切換爲LEADING狀態,其它進程發現已經選舉出新的Leader,那麼它就會切換到FOLLOWING狀態,並開始與Leader保持同步。

3.處於FOLLOWING狀態的進程稱爲Follower,LEADING狀態的進程稱爲Leader。

4.當Leader崩潰或者放棄領導地位時,其餘的Follower進程就會切換到LOOKING狀態開始新一輪的Leader選舉。

運行過程中的狀態轉換
一個Follower只能和一個Leader保持同步,Leader進程和所有的Follower進程之間通過心跳監測機制來感知彼此的情況。

1.若Leader能夠在超時時間內正常的收到心跳檢測,那麼Follower就會一直與該Leader保持連接。

2.如果在指定時間內Leader無法從過半的Follower進程那裏接收到心跳檢測,或者TCP連接斷開,那麼Leader會放棄當前週期的領導,並轉換爲LOOKING狀態;其他的Follower也會選擇放棄這個Leader,同時轉換爲LOOKING狀態,之後會進行新一輪的Leader選舉

ZAB的四個階段

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

這一階段的目的就是爲了選出一個準Leader,然後進入下一階段。

發現階段
在這個階段中,Followers和上一輪選舉出的準Leader進行通信,同步Followers最近接受的事務Proposal。這個階段主要目的是發現當前大多數節點接受的最新提議,並且準Leader生成新的epoch,讓Followers接受,更新它們的acceptedEpoch。

一個Follower只會連接一個Leader,如果有一個節點F認爲另一個Follower P是Leader,F在嘗試連接P時會被拒絕,F被拒絕後,就會進入選舉階段。
ZAB-發現階段
同步階段
同步階段主要是利用 Leader 前一階段獲得的最新 Proposal 歷史,同步集羣中所有的副本。

只有當 quorum(超過半數的節點) 都同步完成,準 Leader 纔會成爲真正的 Leader。Follower 只會接收 zxid 比自己 lastZxid 大的 Proposal。
ZAB同步階段
廣播階段
到了這個階段,Zookeeper 集羣才能正式對外提供事務服務,並且 Leader 可以進行消息廣播。同時,如果有新的節點加入,還需要對新節點進行同步。需要注意的是,Zab 提交事務並不像 2PC 一樣需要全部 Follower 都 Ack,只需要得到 quorum(超過半數的節點)的Ack 就可以。
ZAB廣播階段
ZAB協議實現

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

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

快速選舉(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 決定如何同步數據。這裏的實現跟前面的 階段 3 有所不同:Follower 收到 TRUNC 指令會終止 L.lastCommitedZxid 之後的 Proposal ,收到 DIFF 指令會接收新的 Proposal。

history.lastCommittedZxid:最近被提交的提議的 zxid history.oldThreshold:被認爲已經太舊的已提交提議的 zxid
在這裏插入圖片描述
廣播階段(Broadcast Phase)

參考 4.1 [ZAB協議內容#消息廣播]

ZAB與Paxos的聯繫和區別

聯繫
1.都存在一個類似Leader進程的角色,由其負責協調多個Follower進程的運行

2.Leader進程都會等待超過半數的Follower作出正確的反饋後,纔會將一個提議進行提交(過半原則)

3.在ZAB中,每個Proposal中都包含了一個epoch值,用來代表當前Leader週期,在Paxos中同樣存在這樣的一個表示,名字爲 Ballot。

區別

1.Paxos算法中,新選舉產生的主進程會進行兩個階段的工作;第一階段稱爲讀階段:新的主進程和其他進程通信來收集主進程提出的提議,並將它們提交。第二階段稱爲寫階段:當前主進程開始提出自己的提議。

2.ZAB協議在Paxos基礎上添加了同步階段,此時,新的Leader會確保存在過半的Follower已經提交了之前Leader週期中的所有事物Proposal。這一同步階段的引入,能夠有效保證,Leader在新的週期中提出事務Proposal之前,所有的進程都已經完成了對之前所有事務Proposal的提交。

總的來說,ZAB協議和Paxos算法的本質區別在於兩者的設計目的不一樣:ZAB協議主要用於構建一個高可用的分佈式數據主備系統,而Paxos算法則用於構建一個分佈式的一致性狀態機系統。

總結

問題解答:

1.主從架構下,leader 崩潰,數據一致性怎麼保證?

leader 崩潰之後,集羣會選出新的 leader,然後就會進入恢復階段,新的 leader 具有所有已經提交的提議,因此它會保證讓 followers 同步已提交的提議,丟棄未提交的提議(以 leader 的記錄爲準),這就保證了整個集羣的數據一致性。

2.選舉 leader 的時候,整個集羣無法處理寫請求的,如何快速進行 leader 選舉?

這是通過 Fast Leader Election 實現的,leader 的選舉只需要超過半數的節點投票即可,這樣不需要等待所有節點的選票,能夠儘早選出 leader。

來源 | https://urlify.cn/RRziQf

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章