基于zookeeper3.4.6的源码研究(三)
下面我來說說選leader算法。
首先創(chuàng)建一張給自己的選票,填上自己的myid,zxid和epoch(這些值在前面都已經(jīng)撿算出來的)
如果electionType=0,UDP算法的選舉,這個(gè)暫時(shí)不管。
我們主要討論下3:FastLeaderElection
1.首先要開啟選舉監(jiān)聽端口
2.啟動(dòng)后初始狀態(tài)為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);廣播出去后開始等待,如果等不到回復(fù),則檢查網(wǎng)絡(luò)或重新廣播 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如果對(duì)方也是looking狀態(tài),則看他的logiclock,
①.如果他的logiclock大于自己的,則更新自己的logiclock并清除自己接受的所有選票(recvset,這是一個(gè)map,保留每個(gè)server最新的提議),然后開始雙方開始pk,
誰贏誰輸,全在一個(gè)方法totalOrderPredicate,這個(gè)很重要,這是fast paxos的選票核心算法,但是很簡(jiǎn)單,就是先比epoch,再比zxid,最后是myid。
return ((newEpoch > curEpoch) || ((newEpoch == curEpoch) &&((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));如果對(duì)方勝出,則自己更新為對(duì)方的提議,否則還是用自己的,然后再一次將結(jié)果廣播②.如果他的logiclock小于自己的,則認(rèn)為對(duì)方消息是過時(shí)的,忽略掉。注意這里只是忽略掉,zookeeper什么都沒做,因?yàn)閷?duì)端會(huì)收到自己的廣播消息,在他那邊走①的操作。
③.如果他的logiclock等于自己的,則雙方pk,取勝出者提議。這里跟①不同的地方是不用清除自己接受的選票,因?yàn)閘ogiclock的狀態(tài),表示自己和對(duì)方是在同一步驟的
做完上述后,將對(duì)方的選票更新到recvset,然后統(tǒng)計(jì)該提議是否占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);如果超過半數(shù)了,這時(shí)我們還不能急著下結(jié)論,防止被提議的leader后續(xù)有變,我們還需要遍歷后面的接收消息,看看有沒有更優(yōu)的(pk勝利的),如果還有我們將取出的消息放回去,進(jìn)入下次循環(huán)。
// 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;}}如果沒有,我們則根據(jù)提議的投票設(shè)置自己為follower還是leader,并結(jié)束選舉 self.setPeerState((proposedLeader == self.getId()) ?ServerState.LEADING: learningState());Vote endVote = new Vote(proposedLeader,proposedZxid,logicalclock,proposedEpoch);leaveInstance(endVote);return endVote;2.2對(duì)方是observer,則直接退出,沒有選舉
2.3對(duì)方是follower/leader,需要做的事如下:
如果收到一個(gè)投票,logiclock跟自己一樣,并且他的投票獲勝了,這時(shí)我們要注意檢查他選舉的leader是不是還活著或者已經(jīng)不是leader了,如果是對(duì)的,我們需要根據(jù)這個(gè)投票,將自己設(shè)置為leader還是follower,結(jié)束投票
如果logiclock跟自己不一樣,則當(dāng)對(duì)方pk贏了后我們要更新為對(duì)方的提議,并設(shè)置自己為leader還是follower。
最后將這個(gè)最后的投票保留在CurrentVote中結(jié)束。
綜上所述,paxos是一個(gè)很簡(jiǎn)單也很復(fù)雜的協(xié)議。他的簡(jiǎn)單在于投票的規(guī)則,epoch>zxid>myid。他的復(fù)雜在于每個(gè)server與其他的server的溝通交互。大家協(xié)同按照這個(gè)規(guī)則來辦事,直到完成這個(gè)任務(wù)。總結(jié)一下算法,就是剛開始大家競(jìng)爭(zhēng),憑借實(shí)力當(dāng)leader。當(dāng)leader確定后,后來者無論實(shí)力如何都要被動(dòng)接受后來者不可造次的結(jié)局。
總結(jié)
以上是生活随笔為你收集整理的基于zookeeper3.4.6的源码研究(三)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数组的索引、切片
- 下一篇: Keil5软件仿真debug闪退问题