ZooKeeper為高可用的一致性協調框架,自然的ZooKeeper也有着一致性算法的實現,ZooKeeper使用的是ZAB協議作為數據一致性的算法, ZAB(ZooKeeper Atomic Broadcast ) 全稱為:原子消息廣播協議;
ZAB可以說是在Paxos算法基礎上進行了擴展改造而來的,ZAB協議設計了支持崩潰恢復,ZooKeeper使用單一主進程Leader用於處理客戶端所有事務請求,采用ZAB協議將服務器數狀態以事務形式廣播到所有Follower上;
由於事務間可能存在着依賴關系,ZAB協議保證Leader廣播的變更序列被順序的處理,:一個狀態被處理那么它所依賴的狀態也已經提前被處理;
ZAB協議支持的崩潰恢復可以保證在Leader進程崩潰的時候可以重新選出Leader並且保證數據的完整性;
在ZooKeeper中所有的事務請求都由一個主服務器也就是Leader來處理,其他服務器為Follower,Leader將客戶端的事務請求轉換為事務Proposal,並且將Proposal分發給集群中其他所有的Follower,然后Leader等待Follwer反饋,當有 過半數(>=N/2+1) 的Follower反饋信息后,Leader將再次向集群內Follower廣播Commit信息,Commit為將之前的Proposal提交;
ZooKeeper從以下幾點保證了數據的一致性
① 順序一致性
來自任意特定客戶端的更新都會按其發送順序被提交。也就是說,如果一個客戶端將Znode z的值更新為a,在之后的操作中,它又將z的值更新為b,則沒有客戶端能夠在看到z的值是b之后再看到值a(如果沒有其他對z的更新)。
② 原子性
每個更新要么成功,要么失敗。這意味着如果一個更新失敗,則不會有客戶端會看到這個更新的結果。
③ 單一系統映像
一個客戶端無論連接到哪一台服務器,它看到的都是同樣的系統視圖。這意味着,如果一個客戶端在同一個會話中連接到一台新的服務器,它所看到的系統狀態不會比在之前服務器上所看到的更老。當一台服務器出現故障,導致它的一個客戶端需要嘗試連接集合體中其他的服務器時,所有滯后於故障服務器的服務器都不會接受該連接請求,除非這些服務器趕上故障服務器。
④ 持久性
一個更新一旦成功,其結果就會持久存在並且不會被撤銷。這表明更新不會受到服務器故障的影響。
==========================================================================
ZAB協議的兩個基本模式:恢復模式和廣播模式
恢復模式:(選舉)
當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數server完成了和leader的狀態同步以后,恢復模式就結束了。狀態同步保證了leader和server具有相同的系統狀態。
具體選舉看下面文章
http://www.jasongj.com/zookeeper/fastleaderelection/
崩潰恢復過程中,為了保證數據一致性需要處理特殊情況:
1、已經被leader提交的proposal確保最終被所有的服務器follower提交
2、確保那些只在leader被提出的proposal被丟棄
針對這個要求,如果讓leader選舉算法能夠保證新選舉出來的Leader服務器擁有集群中所有機器最高的ZXID事務proposal,就可以保證這個新選舉出來的Leader一定具有所有已經提交的提案,也可以省去Leader服務器檢查proposal的提交與丟棄的工作。
廣播模式:(數據同步)
一旦Leader已經和多數的Follower進行了狀態同步后,他就可以開始廣播消息了,即進入廣播狀態。
這時候當一個Server加入ZooKeeper服務中,它會在恢復模式下啟動,發現Leader,並和Leader進行狀態同步。待到同步結束,它也參與消息廣播。
ZooKeeper服務一直維持在廣播狀態,直到Leader崩潰了或者Leader失去了大部分的Followers支持。
廣播模式極其類似於分布式事務中的2pc(two-phrase commit 兩階段提交):即Leader提起一個決議,由Followers進行投票,Leader對投票結果進行計算決定是否通過該決議,如果通過執行該決議(事務),否則什么也不做。
廣播協議在所有的通訊過程中使用TCP的FIFO信道,通過使用該信道,使保持有序性變得非常的容易。通過FIFO信道,消息被有序的deliver。只要收到的消息一被處理,其順序就會被保存下來。
Leader會廣播已經被deliver的Proposal消息。在發出一個Proposal消息前,Leader會分配給Proposal一個單調遞增的唯一id,稱之為zxid。
廣播是把Proposal封裝到消息當中,並添加到指向Follower的輸出隊列中,通過FIFO信道發送到Follower。
當Follower收到一個Proposal時,會將其寫入到磁盤,可以的話進行批量寫入。一旦被寫入到磁盤媒介當中,Follower就會發送一個ACK給Leader。
當Leader收到了指定數量的ACK時,Leader將廣播commit消息並在本地遞交該消息。當收到Leader發來commit消息時,Follower也會遞交該消息。
ZAB協議簡化了2PC事務提交:
1、去除中斷邏輯移除,follower要么ack,要么拋棄Leader;
2、leader不需要所有的Follower都響應成功,只要一個多數派ACK即可。
丟棄的事務proposal處理過程:
ZAB協議中使用ZXID作為事務編號,ZXID為64位數字,低32位為一個遞增的計數器,每一個客戶端的一個事務請求時Leader產生新的事務后該計數器都會加1,
高32位為Leader周期epoch編號,當新選舉出一個Leader節點時Leader會取出本地日志中最大事務Proposal的ZXID解析出對應的epoch把該值加1作為新的epoch,將低32位從0開始生成新的ZXID;
ZAB使用epoch來區分不同的Leader周期,能有效避免了不同的leader服務器錯誤的使用相同的ZXID編號提出不同的事務proposal的異常情況,大大簡化了提升了數據恢復流程;
所以這個崩潰的機器啟動時,也無法成為新一輪的Leader,因為當前集群中的機器一定包含了更高的epoch的事務proposal。
https://www.cnblogs.com/sunddenly/p/4138580.html
http://cailin.iteye.com/blog/2014486/
http://www.jasongj.com/zookeeper/fastleaderelection/
http://www.cnblogs.com/ASPNET2008/p/6421571.html
https://zhuanlan.zhihu.com/p/25594630
http://sunxing.cc/2016/06/14/zookeeper-study001/