基于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 leader
                            while((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确定后,后来者无论实力如何都要被动接受后来者不可造次的结局。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值