`
hui_jing_880210
  • 浏览: 43451 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

zookeeper leader选举

阅读更多

首先我们来看看什么是leader选举。其实这个很好理解,leader选举就像总统选举一样,每人一票,获得多数票的人就当选为总统了。在 zookeeper集群中也是一样,每个节点都会投票,如果某个节点获得超过半数以上的节点的投票,则该节点就是leader节点了。

国家选举总统是为了选一个最高统帅,治理国家。那么zookeeper集群选举的目的又是什么呢?其实这个要清楚明白的解释还是挺复杂的。我们可以 简单点想这个问题:我们有一个zookeeper集群,有好几个节点。每个节点都可以接收请求,处理请求。那么,如果这个时候分别有两个客户端向两个节点 发起请求,请求的内容是修改同一个数据。比如客户端c1,请求节点n1,请求是set a = 1; 而客户端c2,请求节点n2,请求内容是set a = 2;

那么最后a是等于1还是等于2呢? 这在一个分布式环境里是很难确定的。解决这个问题有很多办法,而zookeeper的办法是,我们选一个总统出来,所有的这类决策都提交给总统一个人决策,那之前的问题不就没有了么。

那我们现在的问题就是怎么来选择这个总统呢? 在现实中,选择总统是需要宣讲拉选票的,那么在zookeeper的世界里这又如何处理呢?我们还是show code吧。

在QuorumPeer的startLeaderElection方法里包含leader选举的逻辑。Zookeeper默认提供了4种选举方式,默认是第4种: FastLeaderElection。

我们先假设我们这是一个崭新的集群,崭新的集群的选举和之前运行过一段时间的选举是有稍许不同的,后面会提及。

节点状态: 每个集群中的节点都有一个状态 LOOKING, FOLLOWING, LEADING, OBSERVING。都属于这4种,每个节点启动的时候都是LOOKING状态,如果这个节点参与选举但最后不是leader,则状态是 FOLLOWING,如果不参与选举则是OBSERVING,leader的状态是LEADING。

开始这个选举算法前,每个节点都会在zoo.cfg上指定的监听端口启动监听(server.1=127.0.0.1:20881:20882),这里的20882就是这里用于选举的端口。

在FastLeaderElection里有一个Manager的内部类,这个类里有启动了两个线 程:WorkerReceiver, WorkerSender。为什么说选举这部分复杂呢,我觉得就是这些线程就像左右互搏一样,非常难以理解。顾名思 义,这两个线程一个是处理从别的节点接收消息的,一个是向外发送消息的。对于外面的逻辑接收和发送的逻辑都是异步的。

这里配置好了,QuorumPeer的run方法就开始执行了,这里实现的是一个简单的状态机。因为现在是LOOKING状态,所以进入LOOKING的分支,调用选举算法开始选举了:

setCurrentVote(makeLEStrategy().lookForLeader());

而在lookForLeader里主要是干什么呢?首先我们会更新一下一个叫逻辑时钟的东西,这也是在分布式算法里很重要的一个概念,但是在这里先 不介绍,可以参考后面的论文。然后决定我要投票给谁。不过zookeeper这里的选举真直白,每个节点都选自己(汗),选我,选我,选我...... 然后向其他节点广播这个选举信息。这里实际上并没有真正的发送出去,只是将选举信息放到由WorkerSender管理的一个队列里。

复制代码
synchronized(this){
    //逻辑时钟           
    logicalclock++;
    //getInitLastLoggedZxid(), getPeerEpoch()这里先不关心是什么,后面会讨论
    updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());
}

//getInitId() 即是获取选谁,id就是myid里指定的那个数字,所以说一定要唯一
private long getInitId(){
        if(self.getQuorumVerifier().getVotingMembers().containsKey(self.getId()))       
            return self.getId();
        else return Long.MIN_VALUE;
}

//发送选举信息,异步发送
sendNotifications();
复制代码

现在我们去看看怎么把投票信息投递出去。这个逻辑在WorkerSender里,WorkerSender从sendqueue里取出投票,然后交 给QuorumCnxManager发送。因为前面发送投票信息的时候是向集群所有节点发送,所以当然也包括自己这个节点,所以 QuorumCnxManager的发送逻辑里会判断,如果这个要发送的投票信息是发送给自己的,则不发送了,直接进入接收队列。

复制代码
public void toSend(Long sid, ByteBuffer b) {
        if (self.getId() == sid) {
             b.position(0);
             addToRecvQueue(new Message(b.duplicate(), sid));
        } else {
             //发送给别的节点,判断之前是不是发送过
             if (!queueSendMap.containsKey(sid)) {
                 //这个SEND_CAPACITY的大小是1,所以如果之前已经有一个还在等待发送,则会把之前的一个删除掉,发送新的
                 ArrayBlockingQueue<ByteBuffer> bq = new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY);
                 queueSendMap.put(sid, bq);
                 addToSendQueue(bq, b);

             } else {
                 ArrayBlockingQueue<ByteBuffer> bq = queueSendMap.get(sid);
                 if(bq != null){
                     addToSendQueue(bq, b);
                 } else {
                     LOG.error("No queue for server " + sid);
                 }
             }
             //这里是真正的发送逻辑了
             connectOne(sid);
                
        }
    }
复制代码

connectOne就是真正发送了。在发送之前会先把自己的id和选举地址发送过去。然后判断要发送节点的id是不是比自己的id大,如果大则不 发送了。如果要发送又是启动两个线程:SendWorker,RecvWorker(这种一个进程内许多不同种类的线程,各自干活的状态真的很难理解)。 发送逻辑还算简单,就是从刚才放到那个queueSendMap里取出,然后发送。并且发送的时候将发送出去的东西放到一个 lastMessageSent的map里,如果queueSendMap里是空的,就发送lastMessageSent里的东西,确保对方一定收到 了。

看完了SendWorker的逻辑,再来看看数据接收的逻辑吧。还记得前面提到的有个Listener在选举端口上启动了监听么,现在这里应该接收 到数据了。我们可以看到receiveConnection方法。在这里,如果接收到的的信息里的id比自身的id小,则断开连接,并尝试发送消息给这个 id对应的节点(当然,如果已经有SendWorker在往这个节点发送数据,则不用了)。

如果接收到的消息的id比当前的大,则会有RecvWorker接收数据,RecvWorker会将接收到的数据放到recvQueue里。

而FastLeaderElection的WorkerReceiver线程里会不断地从这个recvQueue里读取Message处理。在 WorkerReceiver会处理一些协议上的事情,比如消息格式等。除此之外还会看看接收到的消息是不是来自投票成员。如果是投票成员,则会看看这个 消息里的状态,如果是LOOKING状态并且当前的逻辑时钟比投票消息里的逻辑时钟要高,则会发个通知过去,告诉谁是leader。在这里,刚刚启动的崭 新集群,所以逻辑时钟基本上都是相同的,所以这里还没判断出谁是leader。不过在这里我们注意到如果当前节点的状态是LOOKING的话,接收逻辑会 将接收到的消息放到FastLeaderElection的recvqueue里。而在FastLeaderElection会从这个recvqueue 里读取东西。

这里就是选举的主要逻辑了:totalOrderPredicate

protected boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch) {return ((newEpoch > curEpoch) || 
                ((newEpoch == curEpoch) &&
                ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));
    }

1. 判断消息里的epoch是不是比当前的大,如果大则消息里id对应的server我就承认它是leader

2. 如果epoch相等则判断zxid,如果消息里的zxid比我的大我就承认它是leader

3. 如果前面两个都相等那就比较一下server id吧,如果比我的大我就承认它是leader。

关于前面两个东西暂时我们不去关心它,对于新启动的集群这两者都是相等的。

那这样看来server id的大小也是leader选举的一环啊(有的人生下来注定就不平凡,这都是命啊)。

最后我们来看看,很多文章所介绍的,如果超过一半的人说它是leader,那它就是leader的逻辑吧

复制代码
private boolean termPredicate(
            HashMap<Long, Vote> votes,
            Vote vote) {

        HashSet<Long> set = new HashSet<Long>();
        //遍历已经收到的投票集合,将等于当前投票的集合取出放到set中
        for (Map.Entry<Long,Vote> entry : votes.entrySet()) {
            if (self.getQuorumVerifier().getVotingMembers().containsKey(entry.getKey())
                    && vote.equals(entry.getValue())){
                set.add(entry.getKey());
            }
        }
        
        //统计set,也就是投某个id的票数是否超过一半
        return self.getQuorumVerifier().containsQuorum(set);
    }

    public boolean containsQuorum(Set<Long> ackSet) {
        return (ackSet.size() > half);
    }
复制代码

最后一关:如果选的是自己,则将自己的状态更新为LEADING,否则根据type,要么是FOLLOWING,要么是OBSERVING。

到这里选举就结束了。

这里介绍的是一个新集群启动时候的选举过程,启动的时候就是根据zoo.cfg里的配置,向各个节点广播投票,一般都是选投自己。然后收到投票后就会进行进行判断。如果某个节点收到的投票数超过一半,那么它就是leader了。 

了解了这个过程,我们来看看另外一个问题:

一个集群有3台机器,挂了一台后的影响是什么?挂了两台呢? 

挂了一台:挂了一台后就是收不到其中一台的投票,但是有两台可以参与投票,按照上面的逻辑,它们开始都投给自己,后来按照选举的原则,两个人都投票 给其中一个,那么就有一个节点获得的票等于2,2 > (3/2)=1 的,超过了半数,这个时候是能选出leader的。

挂了两台: 挂了两台后,怎么弄也只能获得一张票, 1 不大于 (3/2)=1的,这样就无法选出一个leader了。

分享到:
评论

相关推荐

    fast paxos算法与zookeeper leader选举源代码分析.doc

    fast paxos算法与zookeeper leader选举源代码分析.doc

    面试官:说一说Zookeeper中Leader选举机制.doc

    Zookeeper 中 Leader 选举机制 在分布式系统中,Leader 选举机制是非常重要的一环,Zookeeper 作为一个广泛应用于分布式系统的协调服务,自然也有自己的 Leader 选举机制。下面,我们将通过一个有趣的面试对话来...

    C# 关于zookeeper主从选举的源码

    - 理解选举过程中的状态转换,比如从follower到candidate再到leader的转变,以及这些状态如何在代码中体现。 6. **应用与实践**: - 这段C#源码对于学习分布式系统、Zookeeper工作原理和C#网络编程都有很大帮助。...

    zookeeperMaster选举以及数据同步代码

    在分布式系统中,Zookeeper是一个至关重要的组件,它主要用于实现分布式服务管理,提供诸如配置管理、命名服务、集群同步、 leader选举等核心功能。在这个"zookeeperMaster选举以及数据同步代码"项目中,我们将深入...

    3、zookeeper的选举

    Leader选举是Zookeeper集群中的重要环节,它分为集群初始化启动时的选举和运行期间的Leader重新选举两种情况。在深入理解选举机制之前,我们需要先了解Zookeeper节点的四种状态以及事务ID的概念。 1. 节点状态: -...

    Zookeeper源码剖析:深入理解Leader选举机制

    **Zookeeper源码剖析:深入理解Leader选举机制** 在分布式协调服务Zookeeper中,Leader选举是其核心功能之一,确保了服务的高可用性和一致性。本文将深入Zookeeper的源码,探讨Leader选举的实现机制。 **为什么要...

    zookeeper选举机制图

    zookeeper选举机制图,内讲述了zookeeper是如何选举出leader、fllower的

    03-05-07-zookeeper原理之Leader选举源码分析1

    Zookeeper 是一个分布式协调服务,源自 Google 的 Chubby,它主要解决了在分布式环境中如何选举主节点(Master Server)的问题,确保一致性。为了实现这一目标,Zookeeper 采用了基于 Paxos 算法的 ZAB(Zookeeper ...

    Zookeeper双机房容灾方案.pdf

    模拟场景1:模拟目的场景概述是指模拟Zookeeper集群的leader选举过程。操作步骤包括:1. 每个server发出一个投票;2. 接受来自各个服务器的投票;3. 处理投票;4. 统计投票;5. 改变服务器状态。 模拟场景2:模拟...

    1、zookeeper3.7.1安装与验证

    其中,`2888`是follower与leader通信的端口,`3888`是选举时使用的端口。 6. **启动Zookeeper**: 在每台服务器上,以`alanchan`用户启动Zookeeper服务。使用`bin/zkServer.sh start`命令启动服务,通过`bin/zk...

    使用Zookeeper来为你的程序加上Leader Election的功能。

    如果 Leader 节点宕机,ZooKeeper 会自动触发新一轮的选举,选择新的 Leader。 在实际应用中,你需要按照以下步骤来使用 ZooKeeper 实现 Leader Election: 1. **初始化连接**:首先,每个节点需要连接到 ...

    leader-selector-demo.rar

    《分布式系统中的Leader选举:基于Zookeeper的Demo详解》 在分布式系统中,一致性是至关重要的,而实现一致性的一种常见机制就是通过Leader选举。在这个过程中,集群中的节点通过一定的算法来确定一个领导节点,这...

    apache zookeeper使用方法实例详解

    ZooKeeper 的主要特点是提供了一个简洁的接口,开发人员可以使用 ZooKeeper 提供的现成服务来实现分布式系统的配置管理、组管理、Leader 选举等功能。 ZooKeeper 的使用方法实例详解可以分为四个基本要求:(1)...

    zookeeper配置.docx

    当 Leader 服务器挂掉时,Follower 服务器将会选举出一个新的 Leader 服务器,以确保集群的可用性。 结论 Zookeeper 配置和集群操作是非常重要的,它们是 Zookeeper 的核心组件。通过对 Zookeeper 配置和集群操作...

    ZooKeeper 原理及其在 Hadoop 和 HBase 中的应用

    1. **Leader选举**:当ZooKeeper集群启动时,所有Follower节点会发起选举过程来选出一个Leader。选举算法基于ZAB协议,确保集群能够在短时间内选举出Leader,即使在网络分区或节点故障的情况下也能保持一致性。 2. ...

    zookeeper linux集群搭建流程

    在选举模式下,ZooKeeper 节点之间不能相互通信,需要选举出一个 leader 节点来恢复集群。 ZooKeeper 应用场景 ZooKeeper 广泛应用于分布式系统中,例如分布式配置管理、分布式锁、分布式队列等。ZooKeeper 的高...

    zookeeper 系列整理总结

    ZooKeeper通过 zab(ZooKeeper Atomic Broadcast)协议保证了强一致性,而Leader选举则是ZooKeeper集群中实现高可用性的关键过程,确保即使有服务器故障,服务仍能继续运行。 总的来说,ZooKeeper是一个强大的工具...

    zookeeper源码

    Zookeeper集群由多个服务器节点组成,每个节点都是对等的,通过选举机制选出一个Leader,其余节点作为Follower。当客户端发起请求时,请求首先发送到Leader,由Leader负责协调整个集群的一致性操作。 二、数据模型 ...

    zookeeper-3.4.12--.rar

    当新的 Leader 选举发生时,Zookeeper 使用 zab 协议来确保选举过程的原子性和最终一致性。 6. **配置管理** ZooKeeper 能够作为配置中心,集中存储和管理分布式应用的配置信息。应用程序可以动态地获取和更新配置...

Global site tag (gtag.js) - Google Analytics