`

zookeeper3.3.3源码分析(二)FastLeader选举算法

阅读更多

 如何在zookeeper集群中选举出一个leader,zookeeper使用了三种算法,具体使用哪种算法,在配置文件中是可以配置的,对应的配置项是”electionAlg”,其中1对应的是LeaderElection算法,2对应的是AuthFastLeaderElection算法,3对应的是FastLeaderElection算法.默认使用FastLeaderElection算法.其他两种算法我没有研究过,就不多说了.

要理解这个算法,最好需要一些paxos算法的理论基础.

1) 数据恢复阶段
首先,每个在zookeeper服务器先读取当前保存在磁盘的数据,zookeeper中的每份数据,都有一个对应的id值,这个值是依次递增的,换言之,越新的数据,对应的ID值就越大.

2) 首次发送自己的投票值
在读取数据完毕之后,每个zookeeper服务器发送自己选举的leader,这个协议中包含了以下几部分的数据:
1)所选举leader的id(就是配置文件中写好的每个服务器的id) ,在初始阶段,每台服务器的这个值都是自己服务器的id,也就是它们都选举自己为leader.
2) 服务器最大数据的id,这个值大的服务器,说明存放了更新的数据.
3)逻辑时钟的值,这个值从0开始递增,每次选举对应一个值,也就是说:如果在同一次选举中,那么这个值应该是一致的 2)逻辑时钟值越大,说明这一次选举leader的进程更新.
4) 本机在当前选举过程中的状态,有以下几种:LOOKING,FOLLOWING,OBSERVING,LEADING,顾名思义不必解释了吧.

    每台服务器将自己服务器的以上数据发送到集群中的其他服务器之后,同样的也需要接收来自其他服务器的数据,它将做以下的处理:
1) 如果所接收数据服务器的状态还是在选举阶段(LOOKING 状态),那么首先判断逻辑时钟值,又分为以下三种情况:
a) 如果发送过来的逻辑时钟大于目前的逻辑时钟,那么说明这是更新的一次选举,此时需要更新一下本机的逻辑时钟值,同时将之前收集到的来自其他服务器的选举清空,因为这些数据已经不再有效了.然后判断是否需要更新当前自己的选举情况.在这里是根据选举leader id,保存的最大数据id来进行判断的,这两种数据之间对这个选举结果的影响的权重关系是:首先看数据id,数据id大者胜出;其次再判断leader id,leader id大者胜出.然后再将自身最新的选举结果(也就是上面提到的三种数据广播给其他服务器).代码如下:

if (n.epoch > logicalclock) {
logicalclock = n.epoch;
recvset.clear();
if(totalOrderPredicate(n.leader, n.zxid,getInitId(), getInitLastLoggedZxid()))
   updateProposal(n.leader, n.zxid);
else
updateProposal(getInitId(),getInitLastLoggedZxid());

sendNotifications();

    其中的totalOrderPredicate函数就是根据发送过来的封包中的leader id,数据id来与本机保存的相应数据进行判断的函数,返回true说明需要更新数据,于是调用updateProposal函数更新数据

b) 发送过来数据的逻辑时钟小于本机的逻辑时钟
说明对方在一个相对较早的选举进程中,这里只需要将本机的数据发送过去就是了

c) 两边的逻辑时钟相同,此时也只是调用totalOrderPredicate函数判断是否需要更新本机的数据,如果更新了再将自己最新的选举结果广播出去就是了.

实际上,在处理选票之前,还有一个预处理的动作,它发生在刚刚接收到关于vote的message的时候,具体过程如下:

1.判断message的来源是不是observer,如果是,则告诉该observer我当前认为的Leader的信息,否则进入2
2.判断message是不是vote信息,是则进入3
3.根据message创建一张vote
4.如果当前server处理LOOKING状态,将vote放入自己的投票箱,而且如果vote源server处于LOOKING状态同时vote源server的选举时旧的,则当前server通知它新的一轮投票;
5如果当前server不处于LOOKING状态而vote源server处理LOOKING状态,则当前server告诉它当前的Leader信息。

三种情况的处理完毕之后,再处理两种情况:
1)服务器判断是不是已经收集到了所有服务器的选举状态,如果是那么根据选举结果设置自己的角色(FOLLOWING还是LEADER),然后退出选举过程就是了.
2)即使没有收集到所有服务器的选举状态,也可以判断一下根据以上过程之后最新的选举leader是不是得到了超过半数以上服务器的支持,如果是,那么尝试在200ms内接收一下数据,如果没有新的数据到来,说明大家都已经默认了这个结果,同样也设置角色退出选举过程.
代码如下:

 

/*
* Only proceed if the vote comes from a replica in the
* voting view.
*/
if(self.getVotingView().containsKey(n.sid)){
recvset.put(n.sid, new Vote(n.leader, n.zxid, n.epoch));

//If have received from all nodes, then terminate
if((self.getVotingView().size() == recvset.size()) && (self.getQuorumVerifier().getWeight(proposedLeader) != 0)){
self.setPeerState((proposedLeader == self.getId()) ? ServerState.LEADING: learningState());
leaveInstance();
return new Vote(proposedLeader, proposedZxid);

} else if (termPredicate(recvset,new Vote(proposedLeader, proposedZxid,logicalclock))) {

// Verify if there is any change in the proposed leader
while((n = recvqueue.poll(finalizeWait,TimeUnit.MILLISECONDS)) != null){
if(totalOrderPredicate(n.leader, n.zxid,proposedLeader, proposedZxid)){
   recvqueue.put(n);
   break;
}
}

/*
* This predicate is true once we don't read any new
* relevant message from the reception queue
*/
if (n == null) {
self.setPeerState((proposedLeader == self.getId()) ? ServerState.LEADING: learningState());
if(LOG.isDebugEnabled()){
LOG.debug("About to leave FLE instance: Leader= " + proposedLeader + ", Zxid = " + proposedZxid + ", My id = " + self.getId() + ", My state = " + self.getPeerState());
}

leaveInstance();
return new Vote(proposedLeader,proposedZxid);
}
}
}

 

2) 如果所接收服务器不在选举状态,也就是在FOLLOWING或者LEADING状态
做以下两个判断:
a) 如果逻辑时钟相同,将该数据保存到recvset,如果所接收服务器宣称自己是leader,那么将判断是不是有半数以上的服务器选举它,如果是则设置选举状态退出选举过程
b) 否则这是一条与当前逻辑时钟不符合的消息,那么说明在另一个选举过程中已经有了选举结果,于是将该选举结果加入到outofelection集合中,再根据outofelection来判断是否可以结束选举,如果可以也是保存逻辑时钟,设置选举状态,退出选举过程.
代码如下:

 

if(n.epoch == logicalclock){
recvset.put(n.sid, new Vote(n.leader, n.zxid, n.epoch));
if((n.state == ServerState.LEADING) || (termPredicate(recvset, new Vote(n.leader,n.zxid, n.epoch, n.state))&& checkLeader(outofelection, n.leader, n.epoch)) ){
self.setPeerState((n.leader == self.getId()) ?ServerState.LEADING: learningState());
leaveInstance();
return new Vote(n.leader, n.zxid);
}
}

outofelection.put(n.sid, new Vote(n.leader, n.zxid, n.epoch, n.state));

if(termPredicate(outofelection, new Vote(n.leader,n.zxid, n.epoch, n.state))&& checkLeader(outofelection, n.leader, n.epoch)) {
   synchronized(this){
      logicalclock = n.epoch;
      self.setPeerState((n.leader == self.getId()) ? ServerState.LEADING: learningState());
   }
   leaveInstance();
   return new Vote(n.leader, n.zxid);
}

break;
}
}

 

    以一个简单的例子来说明整个选举的过程.
假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么.

1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态
2) 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态.
3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader.
4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了.
5) 服务器5启动,同4一样,当小弟.
分享到:
评论

相关推荐

    Zookeeper源码分析

    本文将深入剖析Zookeeper的工作原理,以及其内部实现的FastLeader选举算法和Paxos算法。 首先,我们来看Zookeeper的工作原理概述。Zookeeper采用一种基于ZAB协议的分布式一致性模型,该协议是为Zookeeper定制的,...

    Zookeeper源码分析.epub

    Zookeeper源码分析.epub

    zookeeper-3.3.3-API文档-中文版.zip

    赠送jar包:zookeeper-3.3.3.jar; 赠送原API文档:zookeeper-3.3.3-javadoc.jar; 赠送源代码:zookeeper-3.3.3-sources.jar; 包含翻译后的API文档:zookeeper-3.3.3-javadoc-API文档-中文(简体)版.zip 对应...

    apache-zookeeper3.3.3到3.9.2全版本集合

    zookeeper-3.3.3,3.3.4,3.3.5,3.3.6, zookeeper-3.4.0,3.4.1,3.4.10,3.4.11,3.4.12,3.4.13,3.4.14,3.4.2,3.4.3,3.4.4,3.4.5,3.4.6,3.4.7,3.4.8,3.4.9, zookeeper-3.5.0-alpha,3.5.1-alpha,3.5.10,3.5.2-alpha,3.5.3-...

    zookeeper 3.6.3 源码下载

    **源码结构分析** ZooKeeper的源码主要分为以下几个部分: 1. **协议层**:包含ZAB协议的实现,处理消息的发送和接收,保证数据的最终一致性。 2. **服务器端**:包括ServerCnxnFactory(连接工厂)、ZooKeeper...

    zookeeper-3.3.3-API文档-中英对照版.zip

    赠送jar包:zookeeper-3.3.3.jar 赠送原API文档:zookeeper-3.3.3-javadoc.jar 赠送源代码:zookeeper-3.3.3-sources.jar 包含翻译后的API文档:zookeeper-3.3.3-javadoc-API文档-中文(简体)-英语-对照版.zip ...

    自动动手写zookeeper选举算法与心跳同步

    本文将深入探讨Zookeeper中的选举算法和心跳同步机制,这两个概念对于理解Zookeeper如何保证集群的一致性和高可用性至关重要。 首先,让我们从选举算法开始。在Zookeeper中,最常用的选举算法是Fast Paxos,它是在...

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

    - 分析源码时,重点关注类的设计,如`ZookeeperNode`、`ZookeeperLeader`和`ZookeeperFollower`,它们分别代表Zookeeper的节点、领导者和跟随者。 - 查看节点间如何交换信息(如使用TCP套接字或者HTTP请求)以及...

    zookeeper源码分析

    第2章 ZooKeeper之序列化组件源码解析【透视现象,直击本质】 第4章 持久化【高手过招必备】 第6章 服务器启动 【由浅入深,先学好单机版,才能掌握集群版】 第7章 会话管理 【无处不在的会话其实没那么难】 第8章 ...

    zookeeper源码

    Zookeeper采用Paxos算法的变种ZAB(Zookeeper Atomic Broadcast)协议来保证分布式一致性。Zookeeper集群由多个服务器节点组成,每个节点都是对等的,通过选举机制选出一个Leader,其余节点作为Follower。当客户端...

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

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

    用java实现HS和LCR选举算法

    在分布式系统中,选举算法是确保一致性、容错性和稳定性的重要工具。HS(Hunt-Szymanski)算法和LCR(Lamport's Cluster Membership)算法是两种经典的领导者选举算法,常用于分布式环境中的主节点选择或者一致性...

    08_尚硅谷技术之Zookeeper(源码解析)V3.3.pdf

    为了理解和分析Zookeeper如何通过Paxos算法保证数据的一致性,我们可以通过具体的实例来进一步解析。例如,假设有五个议员需要就税率问题进行决议。议员A1提出税率提案,其他议员需要响应。如果A1能够获得大多数议员...

    zookeeper-3.3.3.jar

    动物园管理员服务器 org.apache.zookeeper/zookeeper/3.3.3/zookeeper-3.3.3.jar

    zookeeper源码(注释版)

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终将简单易用的接口和性能高效、功能稳定的系统提供给用户。...

    zookeeper选举机制图

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

    zookeeper-branch-3.5.8.zip

    在3.5.8版本中,Zookeeper使用了FastLeaderElection算法,该算法在选举过程中考虑了网络延迟,确保了选举过程的高效和稳定。当服务器发生故障或者新服务器加入时,这个机制能够快速地重新选举出新的领导者,保证服务...

    zookeeper.-3.3.5.jar

    zookeeper.-3.3.5.jar 工具类

    Dubbo新手入门实例HelloWorld(zookeeper)源码

    【Dubbo新手入门实例HelloWorld(zookeeper)源码】是一个非常适合初学者的教程,它将带你深入了解如何在实际项目中使用Dubbo框架,并结合Zookeeper作为注册中心进行服务治理。Dubbo是阿里巴巴开源的一个高性能、轻量...

    笔记_zookeeper_源码.zip

    - **选举算法**: 当Leader失效时,`Election`类负责新的Leader选举。基于Fast Leader Election算法,它能够快速确定新的领导者。 - **Watcher的实现**: `ZooKeeper`客户端库中的`WatcherManager`管理所有注册的...

Global site tag (gtag.js) - Google Analytics