ZooKeeper leader选举 源码分析

本文详细分析了ZooKeeper的Leader选举算法,重点讲解了核心流程——lookForLeader,以及FastLeaderElection算法的实现。在选举过程中,节点通过比较SID和ZXID来确定Leader,并通过QuorumCnxManager处理网络I/O,实现投票信息的交换,最终达成超过半数节点的共识,完成选举。
摘要由CSDN通过智能技术生成

Leader选举算法

一句话概况选举算法精髓

所有节点都有两个属性,SID:节点ID,zoo.cfg中配置的myid,ZXID:节点当前的最大事务ID
选举的目的就是选目前所有节点中拥有最大ZXID的节点作为Leader,如果拥有的ZXID相同,就选取SID最大的节点作为Leader

选举算法流程解析–lookForLeader

在实现选举的过程中,其实还有很多细节需要注意,那么接下来看下选举的具体细节:

在ZooKeeper中,提供了3种Leader的选举算法,分别是LeaderElection、 UDP版本的FastLeaderElection、TCP版本的FastLeaderElection,可以通过再配置文件zoo.cfg中使用electionAlg属性来指定。从3.4.0版本开始,ZooKeeper废弃了前2种算法,只保留了TCP版本的FastLeaderElection算法。所有算法都实现了Election接口:

public interface Election {
    //选举的核心算法
    public Vote lookForLeader() throws InterruptedException;
    //关闭选举过程中创建了链接及启动的线程
    public void shutdown();
}

先看下选举算法核心部分(FastLeaderElection.lookForLeader)的流程示意图:
选举流程图

lookForLeader详细源码

  1. 每次选举开始,各个节点都会先为自己投票(原子操作),其中logicalclock代表选举逻辑时钟(类比现实中的第十八次全国人大、第十九次全国人大……),这个值从0开始递增,在同一次选举中,各节点的值基本相同,也有例外情况,比如在第18次选举中,某个节点A挂了,其他节点完成了Leader选举,但没过多久,该Leader又挂了,于是进入了第19次Leader选举,同时节点A此时恢复,加入到Leader选举中,那么节点A的logicallock为18,而其他节点的logicallock为19,针对这种情况,节点A的logicallock会被直接更新为19并参与到第19次Leader选举中。
    其中getInitId()是当前节点的serverId, getInitLastLoggedZxid()是当前节点的最大事务ID,getPeerEpoch当前节点选举轮次,即当前节点Zxid的高位代表的epoch其中getInitId()是当前节点的serverId, getInitLastLoggedZxid()是当前节点的最大事务ID,getPeerEpoch当前节点选举轮次,即当前节点Zxid的高位代表的epoch
public Vote lookForLeader() throws InterruptedException {
    {...}
    try {
        HashMap<Long, Vote> recvset = new HashMap<Long, Vote>();
        HashMap<Long, Vote> outofelection = new HashMap<Long, Vote>();
        int notTimeout = finalizeWait;
		//1.初始化选票,首先为自己投票
        synchronized(this){
            logicalclock++;
            updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());
        }

 		//2.向所有节点发送投票信息
        sendNotifications();

        /*
         * Loop in which we exchange notifications until we find a leader
         * 3.循环交换投票直至选出Leader
         */
        while ((self.getPeerState() == ServerState.LOOKING) &&
                (!stop)){...}
        }
}
  1. 向所有节点发送投票信息
private void sendNotifications() {
        for (QuorumServer server : self.getVotingView().values()) {
            long sid = server.id;

            ToSend notmsg = new ToSend(ToSend.mType.notification,
                    proposedLeader, //推荐的leader的id,就是配置文件中写好的每个服务器的id
                    proposedZxid, //推荐的leader的zxid,zookeeper中的每份数据,都有一个对应的zxid值,越新的数据,zxid值就越大
                    logicalclock,    //选举的逻辑时钟
                    QuorumPeer.ServerState.LOOKING,
                    sid,
                    proposedEpoch);
            sendqueue.offer(notmsg);
        }
    }
  1. 循环交换投票直至选出Leader
while ((self.getPeerState() == ServerState.LOOKING) &&
        (!stop)){
   //从接收投票的队列中取出一条投票信息
    Notification n = recvqueue.poll(notTimeout,
            TimeUnit.MILLISECONDS);

    if(n == null){...}
    else if(self.getVotingView().containsKey(n.sid)) {
        switch (n.state) {
        case LOOKING://拿别人的票跟自己对比,谁的更合理,就发出去更合理的选票(类似于冒泡排序算法,每次对比,都选比自己大/小的数)
        case OBSERVING://观察者是不参与Leader选举的
        case FOLLOWING:
        case LEADING://当已经收到LEADING和FOLLOWI
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值