Zookeeper选举机制

 

部分转载于:https://blog.csdn.net/caohongshuang/article/details/84653941

Zookeeper为了保证各节点的协同工作,在工作时需要一个Leader角色,而Zookeerper默认采用FastLeaderElection算法,且投票数大于半数则胜出的机制。

一、相关概念

1、Serverid:服务器ID

这是在配置集群时设置的myid参数文件,比如有三台服务器,编号分别是1,2,3, 分别表示为服务器1、服务器2、服务器3

编号越大在选择算法中的权重越大。

2、Zxid:数据ID

服务器中存放的最大数据ID.

值越大说明数据越新,在选举算法中数据越新权重越大。

3、Epoch:逻辑时钟

或者叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。逻辑时钟起始值为0,每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。如果某台机器宕机,那么这台机器不会参与投票,因此逻辑时钟会比其他的低。

4、Server状态:选举状态

  • LOOKING,竞选状态。
  • FOLLOWING,随从状态,同步leader状态,参与投票。
  • OBSERVING,观察状态,同步leader状态,不参与投票。
  • LEADING,领导者状态。

二、选举机制类型

Zookeeper选举机制有两种类型,分别为全新集群选举和非全新集群选举,下面分别对两种类型进行详细讲解。

1、全新集群初始化选举

全新集群选举是新建搭建起来的,没有数据ID和逻辑时钟的数据影响集群的选举。在集群初始化阶段,当有一台服务器Server1启动时,其单独无法进行和完成Leader选举,当第二台服务器Server2启动时,两台机器此时可以相互通信,每台机器都试图找到Leader,于是进入选举过程。

假设目前有3台服务器,每台服务器均没有数据,它们的编号分别是1,2,3按编号依次启动,它们的选择举过程如下:

(1)服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于竞选状态;

(2)服务器2启动,给自己投票,同时与之前启动的服务器1交换投票信息,其中包括了SID和ZXID,SID就是该台机器的唯一标识(myid),ZXID是事务id,该ID是64位的,分为高32位和低32位。由于是初次投票,此时的ZXID相同,所以比较的就是SID,由于服务器2的编号大所以服务器2胜出,但此此时投票数正好大于半数,所以服务器2成为领导者,服务器1成为小弟;

(3)服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,尽管服务器3的编号大,但之前服务器2已经胜出,所以服务器3只能成为小弟。

2、非全新集群选举

假如此时有5台服务器,并且已经选举出Server3作为Leader,突然Leader(Server3)宕机,那么此时其他四台服务器要进行重新选举,由于Zookeeper集群已经运行过一-段时间,那么服务器中就会存在运行的数据,所以需要引入服务器SID、数据ZXID和逻辑时钟,优中选优,保证Leader是Zookeeper集群中数据最完整的,过程如下:

(1)统计逻辑时钟是否相同。逻辑时钟是分布式系统中用于区分事件的发生顺序的时间机制,其本质是事务队列,分布式集群不能通过时间戳来区分事件先后,只有协调同步有序地处理事务,才能解决分布式系统中的时序问题(即如何定义a在b之前发生),所以因此每进来一个事务就给一个编号,形成队列,存放在leader节点中,并同步到follower节点。逻辑时钟小,则说明途中可能存在宕机问题,因此事务数据不完整,那么该选举结果被忽略,重新投票选举,leader的事务队列必须是最新,最全的;

(2)对比数据ZXID值,逻辑时钟相同时,数据可能还没及时同步,而数据ZXID反应数据的新旧程度,数据ZXID越大的意味数据越新,值大则胜出;

(3)如果逻辑时钟和数据ZXID都相同的情况下,那么比较服务器以(编号),值大则胜出。

 

三、集群要求

zk节点数量必须是大于等于3的奇数。

两台zk毫无可用性,随便其中一台宕机,集群就不能用了;

三台时,集群容错率为1(允许一台非leader节点下线);

四台时,集群容错率还是1,因为第二台下线的时候也会进入恢复模式。

偶数集群并不能带给我们比奇数集群更多的可用性(反而无谓的添加了投票阶段的支出),所以最好还是奇数集群,如果要增加集群的可用性建议还是添加observer节点。

 

四、选举详述

(一)网络IO

每台服务器在启动的过程中,会启动一个QuorumPeerManager,负责各台服务器之间的底层Leader选举过程中的网络通信。

(1) 消息队列

QuorumCnxManager内部维护了一系列的队列,用来保存接收到的、待发送的消息以及消息的发送器,除接收队列以外,其他队列都按照SID分组形成队列集合,如一个集群中除了自身还有3台机器,那么就会为这3台机器分别创建一个发送队列,互不干扰。

    · recvQueue:消息接收队列,用于存放那些从其他服务器接收到的消息。

    · queueSendMap:消息发送队列,用于保存那些待发送的消息,按照SID进行分组。

    · senderWorkerMap:发送器集合,每个SenderWorker消息发送器,都对应一台远程Zookeeper服务器,负责消息的发送,也按照SID进行分组。

    · lastMessageSent:最近发送过的消息,为每个SID保留最近发送过的一个消息。

(2) 建立连接

为了能够相互投票,Zookeeper集群中的所有机器都需要两两建立起网络连接。QuorumCnxManager在启动时会创建一个ServerSocket来监听Leader选举的通信端口(默认为3888)。开启监听后,Zookeeper能够不断地接收到来自其他服务器的创建连接请求,在接收到其他服务器的TCP连接请求时,会进行处理。为了避免两台机器之间重复地创建TCP连接,Zookeeper只允许SID大的服务器主动和其他机器建立连接,否则断开连接。在接收到创建连接请求后,服务器通过对比自己和远程服务器的SID值来判断是否接收连接请求,如果当前服务器发现自己的SID更大,那么会断开当前连接,然后自己主动和远程服务器建立连接。一旦连接建立,就会根据远程服务器的SID来创建相应的消息发送器SendWorker和消息接收器RecvWorker,并启动。

(3) 消息接收与发送

消息接收:由消息接收器RecvWorker负责,由于Zookeeper为每个远程服务器都分配一个单独的RecvWorker,因此,每个RecvWorker只需要不断地从这个TCP连接中读取消息,并将其保存到recvQueue队列中。消息发送:由于Zookeeper为每个远程服务器都分配一个单独的SendWorker,因此,每个SendWorker只需要不断地从对应的消息发送队列中获取出一个消息发送即可,同时将这个消息放入lastMessageSent中。在SendWorker中,一旦Zookeeper发现针对当前服务器的消息发送队列为空,那么此时需要从lastMessageSent中取出一个最近发送过的消息来进行再次发送,这是为了解决接收方在消息接收前或者接收到消息后服务器挂了,导致消息尚未被正确处理。同时,Zookeeper能够保证接收方在处理消息时,会对重复消息进行正确的处理。

(二)FastLeaderElection:选举算法核心

  • 外部投票:特指其他服务器发来的投票。

  • 内部投票:服务器自身当前的投票。

  • 选举轮次:Zookeeper服务器Leader选举的轮次,即logicalclock。

  • PK:对内部投票和外部投票进行对比来确定是否需要变更内部投票。

(1) 选票管理

  • sendqueue:选票发送队列,用于保存待发送的选票。

  • recvqueue:选票接收队列,用于保存接收到的外部投票。

  • WorkerReceiver:选票接收器。其会不断地从QuorumCnxManager中获取其他服务器发来的选举消息,并将其转换成一个选票,然后保存到recvqueue中,在选票接收过程中,如果发现该外部选票的选举轮次小于当前服务器的,那么忽略该外部投票,同时立即发送自己的内部投票。

  • WorkerSender:选票发送器,不断地从sendqueue中获取待发送的选票,并将其传递到底层QuorumCnxManager中。

(2) 算法核心

 

上图展示了FastLeaderElection模块是如何与底层网络I/O进行交互的。

(三)Leader选举的基本流程

1、自增选举轮次。Zookeeper规定所有有效的投票都必须在同一轮次中,在开始新一轮投票时,会首先对logicalclock进行自增操作。

2、初始化选票。在开始进行新一轮投票之前,每个服务器都会初始化自身的选票,并且在初始化阶段,每台服务器都会将自己推举为Leader。

3、发送初始化选票。完成选票的初始化后,服务器就会发起第一次投票。Zookeeper会将刚刚初始化好的选票信息放入sendqueue中,由发送器WorkerSender负责发送出去。

投票信息包含:所选举leader的Serverid,Zxid,逻辑时钟值Epoch(即选举轮次,随着选举轮数的增加而递增)

4、接收外部投票。每台服务器会不断地从recvqueue队列中获取外部选票。如果服务器发现无法获取到任何外部投票,那么就会立即确认自己是否和集群中其他服务器保持着有效的连接,如果没有连接,则马上建立连接,如果已经建立了连接,则再次发送自己当前的内部投票。

5、判断选举轮次。在发送完初始化选票之后,接着开始处理外部投票。在处理外部投票时,会根据选举轮次来进行不同的处理。

· 外部投票的选举轮次大于内部投票。若服务器自身的选举轮次落后于该外部投票对应服务器的选举轮次,那么就会立即更新自己的选举轮次(logicalclock),并且清空所有已经收到的投票,然后使用初始化的投票来进行PK以确定是否变更内部投票。最终再将内部投票发送出去。

· 外部投票的选举轮次小于内部投。若服务器接收的外选票的选举轮次落后于自身的选举轮次,那么Zookeeper就会直接忽略该外部投票,不做任何处理,并返回步骤4。

· 外部投票的选举轮次等于内部投票。此时可以开始进行选票PK。

6、选票PK。在进行选票PK时,符合任意一个条件就需要变更投票。

· 若外部投票中推举的Leader服务器的选举轮次大于内部投票,那么需要变更投票。

· 若选举轮次一致,那么就对比两者的ZXID,若外部投票的ZXID大,那么需要变更投票。

· 若两者的ZXID一致,那么就对比两者的SID,若外部投票的SID大,那么就需要变更投票。

7、变更投票。经过PK后,若确定了外部投票优于内部投票,那么就变更投票,即使用外部投票的选票信息来覆盖内部投票,变更完成后,再次将这个变更后的内部投票发送出去。

8、选票归档。无论是否变更了投票,都会将刚刚收到的那份外部投票放入选票集合recvset中进行归档。recvset用于记录当前服务器在本轮次的Leader选举中收到的所有外部投票(按照服务队的SID区别,如{(1, vote1), (2, vote2)...})。

9、统计投票。完成选票归档后,就可以开始统计投票,统计投票是为了统计集群中是否已经有过半的服务器认可了当前的内部投票,如果确定已经有过半服务器认可了该投票,则终止投票。否则返回步骤4。

10、更新服务器状态。若已经确定可以终止投票,那么就开始更新服务器状态,服务器首选判断当前被过半服务器认可的投票所对应的Leader服务器是否是自己,若是自己,则将自己的服务器状态更新为LEADING,若不是,则根据具体情况来确定自己是FOLLOWING或是OBSERVING。

  以上10个步骤就是FastLeaderElection的核心,其中步骤4-9会经过几轮循环,直到有Leader选举产生。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值