Zookeeper的ZAB協議


一、ZAB 協議

ZAB(Zookeeper Atomic Broadcast) 協議是為分布式協調服務 ZooKeeper 專門設計的一種支持崩潰恢復的原子廣播協議。在 ZooKeeper 中,主要依賴 ZAB 協議來實現分布式數據一致性,基於該協議ZooKeeper 實現了一種主備模式的系統架構來保持集群中各個副本之間的數據一致性。

二、ZAB 協議介紹

ZAB 協議包含兩種基本模式,分別是崩潰恢復和原子廣播。
崩潰恢復:當整個集群在啟動或者當 leader 節點出現網絡中斷、崩潰等情況時,ZAB 協議就會進入恢復模式並選舉產生新的 leader,當 leader 服務器選舉出來后並且集群中有過半的機器和該 leader 節點完成數據同步(用來保證集群中過半的機器能夠和 leader 服務器的數據狀態保持一致)后,ZAB 協議就會退出恢復模式。簡單地說,就是 leader 掛了,然后需要選舉出新的 leader(ZK是有中心化節點的中間件),完成新 leader 和 follower 和 observer 的數據同步。
舉個栗子:國家總統掛了,國家處於緊急狀態,然后選舉出一個新的總統,待新總統完成工作交接后,國家結束緊急狀態。
原子廣播:當集群中已經有過半的 follower 節點完成了和 leader 狀態同步以后,那么整個集群就進入了消息廣播模式。這個時候 leader 節點正常工作,如果啟動一台新的服務器加入到集群,那這個服務器會直接進入數據恢復模式,和 leader 節點進行數據同步。同步完成后即可正常對外提供非事務請求的處理。

需要注意的是:leader 節點可以處理事務請求和非事務請求,follower 節點只能處理非事務請求,如果 follower 節點接收到非事務請求,會把這個請求轉發給 leader 服務器。

三、消息廣播的原理(zxid):消息廣播的過程實際上是一個簡化版本的二階段提交過程。

1. leader 接收到消息請求后,將消息賦予一個全局唯一的64 位自增 id(叫:zxid),通過 zxid 的大小比較既可以實現因果有序這個特征。
2. leader 為每個 follower 准備了一個 FIFO 隊列(通過 TCP協議來實現,以實現了全局有序這一個特點)將帶有 zxid的消息作為一個提案(proposal)分發給所有的 follower。
3. 當 follower 接收到 proposal,先把 proposal 寫到磁盤,寫入成功以后再向 leader 回復一個 ack。
4. 當 leader 接收到合法數量(超過半數節點)的 ACK 后,leader 就會向這些 follower 發送 commit 命令,同時會在本地執行該消息。
5. 當 follower 收到消息的 commit 命令以后會提交該消息。

這里需要注意的是: leader 的投票過程,不需要 Observer 的 ack,也就是 Observer 不需要參與投票過程,但是 Observer 必須要同步 Leader 的數據從而在處理請求的時候保證數據的一致性,用來實現提升讀性能。

四、崩潰恢復的實現原理

前面我們已經清楚了 ZAB 協議中的消息廣播過程,ZAB 協議的這個基於原子廣播協議的消息廣播過程,在正常情況下是沒有任何問題的,但是一旦 leader 節點崩潰或者由於網絡問題導致 leader 服務器失去了過半的 follower 節點的聯系(leader 失去與過半 follower 節點聯系,可能是 leader 節點和 follower 節點之間產生了網絡分區,那么此時的 leader 不再是合法的 leader 了),那么就會進入到崩潰恢復模式。崩潰恢復狀態下 zab 協議需要做兩件事:1. 選舉出新的 leader;2. 數據同步;
ZAB 協議中的崩潰恢復需要保證,如果一個事務 Proposal 在一台機器上被處理成功,那么這個事務應該在所有機器上都被處理成功,哪怕是出現故障。為了達到這個目的,我們先來設想一下,在 zookeeper 中會有哪些場景導致數據不一致性,以及針對這個場景zab 協議中的崩潰恢復應該怎么處理。

1. 已經被處理的消息不能丟:當 leader 收到合法數量 follower 的 acks 后,就向各個 follower 廣播 COMMIT 命令,同時也會在本地執行 COMMIT 並向連接的客戶端返回 acks 。但是如果在各個 follower 在收到 COMMIT 命令前 leader 就掛了,導致剩下的服務器並沒有執行都這條消息。即 leader 在發 commit 命令前掛了(此時 follower 已經將該消息存入本地,只是沒有 commit ),導致 follower 沒有收到這條已經被 leader 處理的消息。

2. 被丟棄的消息不能再次出現:當 leader 接收到消息請求生成 proposal 后就掛了,其他 follower 並沒有收到此 proposal,因此經過恢復模式重新選了 leader 后,這條消息是被跳過的。 此時之前掛了的 leader 重新啟動並注冊成了 follower,他保留了被跳過消息的proposal 狀態,與整個系統的狀態是不一致的,需要將其刪除

ZAB 協議需要滿足上面兩種情況,就必須要設計一個 leader 選舉算法:能夠確保已經被 leader 提交的事務 Proposal 能夠提交、同時丟棄已經被跳過的事務 Proposal。
1. 如果 leader 選舉算法能夠保證新選舉出來的 Leader 服務器擁有集群中所有機器最高編號(ZXID 最大)的事務 Proposal,那么就可以保證這個新選舉出來的 Leader 一定具有已經提交的提案。因為所有提案被 COMMIT 之前必須有超過半數的 follower ACK,即必須有超過半數節點的服務器的事務日志上有該提案的 proposal,因此,只要有合法數量的節點正常工作,就必然有一個節點保存了所有被 COMMIT 消息的 proposal 狀態

2. zxid 是 64 位,高 32 位是 epoch 編號,每經過一次 Leader 選舉產生一個新的 leader,新的 leader 會將 epoch 號+1,低 32 位是消息計數器,每接收到一條消息這個值+1,新 leader 選舉后這個值重置為 0,這樣設計的好處在於老的 leader 掛了以后重啟,它不會被選舉為 leader,因此此時它的 zxid 肯定小於當前新的 leader。當老的 leader 作為 follower 接入新的 leader 后,新的 leader 會讓它將所有的擁有舊的 epoch 號的未被 COMMIT 的 proposal 清除。

選主:leader選舉是zk中最重要的技術之一,也是保證分布式數據一致性的關鍵所在。當集群中的一台服務器處於如下兩種情況之一時,就會進入leader選舉階段——服務器初始化啟動、服務器運行期間無法與leader保持連接。 選舉階段,集群間互傳的消息稱為投票,投票Vote主要包括二個維度的信息:ID、ZXID

  • ID:被推舉的leader的服務器ID,集群中的每個zk節點啟動前就要配置好這個全局唯一的ID。
  • ZXID:被推舉的leader的事務ID ,該值是從機器DataTree內存中取的,即事務已經在機器上被commit過了。

節點進入選舉階段后的大體執行邏輯如下:

  • (1)設置狀態為LOOKING,初始化內部投票Vote (id,zxid) 數據至內存,並將其廣播到集群其它節點。節點首次投票都是選舉自己作為leader,將自身的服務ID、處理的最近一個事務請求的ZXID(ZXID是從內存數據庫里取的,即該節點最近一個完成commit的事務id)及當前狀態廣播出去。然后進入循環等待及處理其它節點的投票信息的流程中。
  • (2)循環等待流程中,節點每收到一個外部的Vote信息,都需要將其與自己內存Vote數據進行PK,規則為取ZXID大的,若ZXID相等,則取ID大的那個投票。若外部投票勝選,節點需要將該選票覆蓋之前的內存Vote數據,並再次廣播出去;同時還要統計是否有過半的贊同者與新的內存投票數據一致,無則繼續循環等待新的投票,有則需要判斷leader是否在贊同者之中,在則退出循環,選舉結束后根據選舉結果及各自角色切換狀態,leader切換成LEADING、follower切換到FOLLOWING、observer切換到OBSERVING狀態。 

偽代碼:

if (接收到的投票的選舉周期 > 本服務器當前的選舉周期) {
    // 修改本服務器的選舉周期為接收到的投票的選舉周期
    // 清空本服務器的投票箱(表示選舉周期落后,重新開始投票)
    // 比較接收到的選票所選擇的服務器與本服務器的數據誰更新,本服務器將選票投給數據較新者
    // 發送選票
} else if(接收到的投票的選舉周期 < 本服務器當前的選舉周期){
    // 接收到的投票的選舉周期落后了,本服務器直接忽略此投票
} else if(選舉周期一致) {
    // 比較接收到的選票所選擇的服務器與本服務器當前所選擇的服務器的數據誰更新,本服務器將選票投給數據較新者
    // 發送選票
}

ZooKeeper集群在進行領導者選舉的過程中不能對外提供服務


免責聲明!

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



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