轉載自:https://www.jianshu.com/p/07114f1ee595
概念
-
logicalclock: ZooKeeper服務器Leader選舉的輪次
-
electionEpoch: 當前服務器的選舉輪次,每次進入新一輪投票後進行加1操作
-
peerEpoch: 被推薦的Leader的選舉輪次
-
外部投票: 特指其他服務器發來的投票
-
內部投票: 服務器自身當前的投票
-
Zookeeper規定了所有有效的投票都必須在同一輪次
ZXID設計
一個ZXID是64位,高32是紀元(epoch)編號,每經過一次leader選舉產生一個新的leader,新leader會將epoch號+1。低32位是消息計數器,每接收到一條消息這個值+1,新leader選舉後這個值重置爲0,可以簡單理解epoch爲皇帝的年後,低位32位爲朝中的大臣,真所謂一朝天子、一朝臣。
選舉流程
ZooKeeper選主的接口是Election,默認的具體實現類是FastLeaderElection,接下來主要走讀下lookForLeader()方法。代碼參考zookeeper-3.4.5
-
當前服務器選舉輪次加1操作
-
更新提案,默認將票投給你自己
-
將提案通知給其他服務器,通知的時候會將logicalclock賦值給electionEpoch,即完成加1操作
沒有外部投票的處理流程
有外部投票的處理流程
-
外部投票的輪次大於內部投票
更新服務器的投票輪次,然後內部投票和外部投票PK,具體PK或得提案,具體PK算法見下圖。 -
中外部投票輪次小於內部投票
直接忽略 -
中外部投票輪次等於內部投票
內部投票和外部投票PK,具體PK算法見下圖
PK算法
-
外部投票中被推薦Leader服務器的選舉輪次大於內部投票,提案變更。
-
輪次相同,外部投票被推薦Leader服務器的ZXID大於內部投票,提案變更。
-
ZXID相同,外部投票被推薦Leader服務器的SID大於內部投票,提案變更。(SID是serverId)
過半投票認可當前內部投票
-
過半投票認可當前內部投票
-
有沒有被推薦的Leader
-
更新服務器狀態(leading,observing,following)
總流程
參考:從Paxos到Zookeeper分佈式一致性原理與實踐
區分外部投票輪次,外部投票中被推薦Leader投票輪次,內部同理
/*
* Epoch 投票輪次
*/
long electionEpoch;
/*
* epoch of the proposed leader 被推薦Leader投票輪次
*/
long peerEpoch;
簡單總結選主流程(模擬選舉一個NB的人)
-
在沒有遇到比我牛的人之前,第一票推薦我自己。
-
我有一個票箱,保存了當前這一輪選舉中自己的推薦人以及接收到的推薦人信息,一人一票,重複或過期的票概不接受,當我發現了比我推薦的牛人還牛的時候,改爲推薦這個牛人,否則,我還是推薦我自己。如果我發現我的選舉輪數落後了,清空票箱,改爲推薦接收到的最新選舉中大家推薦的最牛的那個人(如果沒有人比我牛,那還是推薦我自己)。
-
不斷的重複上面的過程,不斷的告訴別人“我的投票是第幾輪”、“我推舉的人是誰”。直到我的票箱中“我推舉的最牛的人”收到了不少於N/2+1的推舉投票,此時這個人就是我認定的最終leader。
-
當我確定了誰是最終 leader 並且這個 leader 一切正常,我就更新我的狀態爲 FOLLOWING/LEADING(我自己是最終 leader 則是 LEADING 否則就是 FOLLOWING),之後的選舉中都直接反饋我確定的這個最終 leader。
問題
提交已被Leader Commit的事務
發生場景
Leader發送Propose請求,Follower F1和Follower F2都向Leader回覆了ACK,Leader向所有的Follower發送Commit請求並Commit自身,此時Leader宕機,Leader已經Commit,但Follower尚未Commit,數據不一致。
處理方式
選舉F.zxid最大的Follower成爲新的準Leader,由於舊Leader宕機前,半數或以上的Follower曾經發送ACK消息,新的準Leader必然是這半數或以上Follower的一員;新的準Leader會發現自身存在已經Propose但尚未Commit的事務Proposal,新的準Leader會向所有的Follower先發送Propose請求,再發送Commit請求。
丟棄只被Leader Propose的事務
發生場景
Leader收到了事務請求,將其包裝成了事務Proposal,此時Leader宕機,Follower並沒有收到Propose請求,Follower進入選舉階段,選舉產生新Leader,舊的Leader重啓,以Follower的角色加入集羣,此時舊Leader上有一個多餘的事務Proposal,數據不一致。
處理方式
新的準Leader會根據自己服務器上最後被提交的事務Proposal和Follower的事務Proposal進行對比,然後新的準Leader要求Follower執行一個回退操作,回退到一個已經被集羣半數以上機器提交的最新的事務Proposal。
==============================