基于zookeeper3.4.6的源码研究(三)
下面我來說說選leader算法。
首先創建一張給自己的選票,填上自己的myid,zxid和epoch(這些值在前面都已經撿算出來的)
如果electionType=0,UDP算法的選舉,這個暫時不管。
我們主要討論下3:FastLeaderElection
1.首先要開啟選舉監聽端口
2.啟動后初始狀態為looking
private ServerState state = ServerState.LOOKING;(readonlymode.enabled模式的zookeeper不考慮)
更新提議id為myid,提議zxid為自己最新的zxid,epoch也是自己最新的,logicalclock++
并將其廣播出去
for (QuorumServer server : self.getVotingView().values()) {long sid = server.id;ToSend notmsg = new ToSend(ToSend.mType.notification,proposedLeader,proposedZxid,logicalclock,QuorumPeer.ServerState.LOOKING,sid,proposedEpoch);廣播出去后開始等待,如果等不到回復,則檢查網絡或重新廣播 Notification n = recvqueue.poll(notTimeout,TimeUnit.MILLISECONDS);/** Sends more notifications if haven't received enough.* Otherwise processes new notification.*/if(n == null){if(manager.haveDelivered()){sendNotifications();} else {manager.connectAll();}如果收到了返回,首先我們要看它是不是有資格投票,如果是來自observer的消息則直接過濾不看
2.1如果對方也是looking狀態,則看他的logiclock,
①.如果他的logiclock大于自己的,則更新自己的logiclock并清除自己接受的所有選票(recvset,這是一個map,保留每個server最新的提議),然后開始雙方開始pk,
誰贏誰輸,全在一個方法totalOrderPredicate,這個很重要,這是fast paxos的選票核心算法,但是很簡單,就是先比epoch,再比zxid,最后是myid。
return ((newEpoch > curEpoch) || ((newEpoch == curEpoch) &&((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));如果對方勝出,則自己更新為對方的提議,否則還是用自己的,然后再一次將結果廣播②.如果他的logiclock小于自己的,則認為對方消息是過時的,忽略掉。注意這里只是忽略掉,zookeeper什么都沒做,因為對端會收到自己的廣播消息,在他那邊走①的操作。
③.如果他的logiclock等于自己的,則雙方pk,取勝出者提議。這里跟①不同的地方是不用清除自己接受的選票,因為logiclock的狀態,表示自己和對方是在同一步驟的
做完上述后,將對方的選票更新到recvset,然后統計該提議是否占n/2+1,具體參見(一)中的生效算法QuorumVerifier
protected boolean termPredicate(HashMap<Long, Vote> votes,Vote vote) {HashSet<Long> set = new HashSet<Long>();/** First make the views consistent. Sometimes peers will have* different zxids for a server depending on timing.*/for (Map.Entry<Long,Vote> entry : votes.entrySet()) {if (vote.equals(entry.getValue())){set.add(entry.getKey());}}return self.getQuorumVerifier().containsQuorum(set);如果超過半數了,這時我們還不能急著下結論,防止被提議的leader后續有變,我們還需要遍歷后面的接收消息,看看有沒有更優的(pk勝利的),如果還有我們將取出的消息放回去,進入下次循環。
// Verify if there is any change in the proposed leaderwhile((n = recvqueue.poll(finalizeWait,TimeUnit.MILLISECONDS)) != null){if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,proposedLeader, proposedZxid, proposedEpoch)){recvqueue.put(n);break;}}如果沒有,我們則根據提議的投票設置自己為follower還是leader,并結束選舉 self.setPeerState((proposedLeader == self.getId()) ?ServerState.LEADING: learningState());Vote endVote = new Vote(proposedLeader,proposedZxid,logicalclock,proposedEpoch);leaveInstance(endVote);return endVote;2.2對方是observer,則直接退出,沒有選舉
2.3對方是follower/leader,需要做的事如下:
如果收到一個投票,logiclock跟自己一樣,并且他的投票獲勝了,這時我們要注意檢查他選舉的leader是不是還活著或者已經不是leader了,如果是對的,我們需要根據這個投票,將自己設置為leader還是follower,結束投票
如果logiclock跟自己不一樣,則當對方pk贏了后我們要更新為對方的提議,并設置自己為leader還是follower。
最后將這個最后的投票保留在CurrentVote中結束。
綜上所述,paxos是一個很簡單也很復雜的協議。他的簡單在于投票的規則,epoch>zxid>myid。他的復雜在于每個server與其他的server的溝通交互。大家協同按照這個規則來辦事,直到完成這個任務。總結一下算法,就是剛開始大家競爭,憑借實力當leader。當leader確定后,后來者無論實力如何都要被動接受后來者不可造次的結局。
總結
以上是生活随笔為你收集整理的基于zookeeper3.4.6的源码研究(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数组的索引、切片
- 下一篇: Keil5软件仿真debug闪退问题