文章目录


问题

termPredicate这里判断投票是否结束

if (termPredicate(recvset,
                                new Vote(proposedLeader, proposedZxid,
                                        logicalclock.get(), proposedEpoch))) 

FastLeaderElection.termPredicate()

 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()); //如果存在2票,set里面是不是有2个?
            }
        }//对选票进行判断
        //进入containsQuorum   看QuorumMaj
        //判断当前节点的票数是否是大于一半,默认采用 QuorumMaj 来实现
        return self.getQuorumVerifier().containsQuorum(set); //验证
    }

进入QuorumMaj.containsQuorum()

  public boolean containsQuorum(Set<Long> set){
        //这个 half 的值是多少呢?,也就是说,在构建 QuorumMaj 的时候,传递了当前集群节点的数量,这里是 3
        // 那么, hafl=3/2=1 可以在 QuorumPeerConfig.parseProperties 这个方法中,找到如下代码。
        //那么 set.size()>1. 意味着至少要有两个节点的票据是选择你当 leader,否则,还得继续投
        return (set.size() > half); //已经归纳的票据是否大于half .2>1  -> leader选举、 数据同步
    }

那么问题来了,上面的set是保存的是本地读到的投票,那么根据我的理解是不包括自己的投票的,这样的话,set.size()>half set.size()最小是half+1,即servers/2+1,算上本身自己的,也就是当前集群中是servers/2+2的时候表示投票结束?这显然跟众所周知的理论是不一样的,应该是算上自己的票,票数为servers/2+1的时候投票结束。

统计投票信息:server3统计收到的投票(包括自己投的),(1, 123)是两票,server1统计收到的投票(包括自己投的),(1, 123)是两票;

https://tech.souyunku.com/?p=6308

可以看到包括自己投的。

那究竟是为什么呢?

解决

首先,因为还没有看通信部分,所以产生了盲区

因为前面发送投票信息的时候是向集群所有节点发送,所以当然也包括自己这个节点,所以QuorumCnxManager的发送逻辑里会判断,如果这个要发送的投票信息是发送给自己的,则不发送了,直接进入接收队列。
https://www.itcodemonkey.com/article/4644.html

将变更的投票发给集群中所有的Follower节点。server.1将(10, 1)发给集群中所有Follower,包括它自己
https://zhuanlan.zhihu.com/p/60083015

sendNotifications(); //发送投票,包括发送给自己
https://blog.csdn.net/Dongguabai/article/details/82961284

选举的方法中刚开始和本地票发生变化的时候都会执行sendNotifications()方法将本地的票发送出去,这了包括发送给自己

所以上面的set是从 Notification n = recvqueue.poll(notTimeout, TimeUnit.MILLISECONDS);中取的,但是去除来的包含自己本身的票

所以判断投票结束的依据确实是n/2+1(包含自己

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐