ZAB 協議是爲分佈式協調服務 ZooKeeper 專門設計的一種支持崩潰恢復的原子廣播協議。在 ZooKeeper 中,主要依賴 ZAB 協議來實現分佈式數據一致性,基於該協議,ZooKeeper 實現了一種主備模式的系統架構來保持集羣中各個副本之間的數據一致性。服務器
Zab 協議分爲兩大塊:架構
廣播的過程其實是一個簡化的二階段提交過程:分佈式
相比於完整的二階段提交,Zab 協議最大的區別就是不能終止事務,follower 要麼回 ACK 給 leader,要麼拋棄 leader,在某一時刻,leader 的狀態與 follower 的狀態極可能不一致,所以它不能處理 leader 掛掉的狀況,因此 Zab 協議引入了恢復模式來處理這一問題。從另外一角度看,正由於 Zab 的廣播過程不須要終止事務,也就是說不須要全部 follower 都返回 ACK 才能進行 COMMIT,而是隻須要合法數量(2f+1 臺服務器中的 f+1 臺) 的follower,也提高了總體的性能。性能
因爲以前講的 Zab 協議的廣播部分不能處理 leader 掛掉的狀況,Zab 協議引入了恢復模式來處理這一問題。爲了使 leader 掛了後系統能正常工做,須要解決如下兩個問題:設計
這一狀況會出如今如下場景:當 leader 收到合法數量 follower 的 ACKs 後,就向各個 follower 廣播 COMMIT 命令,同時也會在本地執行 COMMIT 並向鏈接的客戶端返回「成功」。可是若是在各個 follower 在收到 COMMIT 命令前 leader 就掛了,致使剩下的服務器並無執行都這條消息。日誌
如圖 1-1,消息 1 的 COMMIT 命令 Server1(leader)和 Server2(follower) 上執行了,可是 Server3 尚未收到消息 1 的 COMMIT 命令,此時 leader Server1 已經掛了,客戶端極可能已經收到消息 1 已經成功執行的回覆,通過恢復模式後須要保證全部機器都執行了消息 1。cdn
爲了實現已經被處理的消息不能丟這個目的,Zab 的恢復模式使用瞭如下的策略:blog
這一狀況會出如今如下場景:當 leader 接收到消息請求生成 proposal 後就掛了,其餘 follower 並無收到此 proposal,所以通過恢復模式從新選了 leader 後,這條消息是被跳過的。 此時,以前掛了的 leader 從新啓動並註冊成了 follower,他保留了被跳過消息的 proposal 狀態,與整個系統的狀態是不一致的,須要將其刪除。隊列
如圖 1-2 ,在 Server1 掛了後系統進入新的正常工做狀態後,消息 3被跳過,此時 Server1 中的 P3 須要被清除。事務
Zab 經過巧妙的設計 zxid 來實現這一目的。一個 zxid 是64位,高 32 是紀元(epoch)編號,每通過一次 leader 選舉產生一個新的 leader,新 leader 會將 epoch 號 +1。低 32 位是消息計數器,每接收到一條消息這個值 +1,新 leader 選舉後這個值重置爲 0。這樣設計的好處是舊的 leader 掛了後重啓,它不會被選舉爲 leader,由於此時它的 zxid 確定小於當前的新 leader。當舊的 leader 做爲 follower 接入新的 leader 後,新的 leader 會讓它將全部的擁有舊的 epoch 號的未被 COMMIT 的 proposal 清除。