6 Leader选举
6.1 Leader选举概述
6.1.1 服务器启动时期的Leader选举
触发条件:集群中至少有两台能够互相通信的机器
Leader选举流程:这里以3台为例,当第二台机器Server2启动后,第一、二台机器都试图找到一个Leader,于是进入Leader选举流程:
6.1.2 服务器运行期间的Leader选举
Leader如果挂了,则进入新一轮的选举,过程与启动时期的选举基本一致
假设正在运行的服务器有三台:
6.2 算法分析
介绍FastLeaderElection
6.2.1 术语解释
SID、ZXID、Vote、Quorum
6.2.2 算法分析
6.2.2.1 进入Leader选举
集群中的一台服务器进入选举的时机:
一台服务器进入Leader选举时,集群可能的状态:
如果已经存在Leader:当该机器试图去选举Leader的时候,会被告知当前服务器的Leader信息,然后和Leader服务器建立连接,并进行状态同步即可
如果不存在Leader:开始进行Leader选举,即第一次投票
例子:
6.2.2.2 开始第一次投票
状态为”LOOKING“,意思是正在寻找Leader;会向集群中所有其他机器发生消息,此消息被称为”投票“
继6.2.2.1例子:
6.2.2.3 变更投票(第二次投票)
每台机器发出自己的投票后,也会接收到来自集群中其他机器的投票
每台机器会根据一定的规则,来处理收到的其他机器的投票,并以此来决定是否需要变更自己的投票(此规则为算法核心);每次对收到的投票的处理,都是一个对(vote_sid,vote_zxid)和(self_sid,self_zxid)对比的过程
术语:
4个规则:
继6.2.2.2例子:
6.2.2.4 确定Leader
经过第二次投票后,集群中的每台机器会再次收到其他机器的投票,然后开始统计投票
如果一台机器收到了超过半数的相同的投票,那么这个投票对应的SID机器即为Leader
继6.2.2.3中例子:
Server3收到Server3、4、5的相同的投票(3,9),所以Server3成为Leader
6.2.3 总结
哪台服务器上的数据越新,则越有可能成为Leader。
因为数据越新,则ZXID越大,也就越能保证数据的恢复;当然如果ZXID相同,则SID大的当Leader,晚加入,说明机器越新,不容易坏
6.3 实现细节
介绍FastLeaderElection算法实现
6.3.1 服务器状态
SeverState类中列举了4种。分别是LOOKING、FOLLOWING、LEADING、OBSERVING:
6.3.2 “投票”的数据结构
基本结构如下:
6.3.3 QuorumCnxManager:网络IO
每台服务器启动的时候,都会启动一个QuorumCnxManager,负责Leader选举过程中服务器之间的底层通信
6.3.4 消息队列
QuorumCnxManager内部维护了一系列的队列,用于保存接收到的、待发送的消息,以及消息的发送器
共同点:按SID分组形成队列集合(除了接收队列)
分组概念:如发送队列,假设集群中除自身外还有4台机器,那么当前服务器就会为这4台服务器分别创建一个发送队列,互不干扰,达到隔离的目的
队列类型:
6.3.5 建立连接
机器需要两两之间建立连接
QuorumCnxManager启动时,会创建一个ServerSocket来监听Leader选举的通信端口(默认3888端口),这样就能不断地接收来自其他服务器的”创建连接“请求;
请求由receiveConnection函数来处理;
为了避免两台机器之间重复创建连接,设计了一种规则:只允许SID大的服务器主动和其他服务器建立连接,否则断开。实现方式为:receiveConnection函数中,服务器通过对比自己和远程服务器的SID值,若自己更大,则断开,然后主动去和远程服务器建立连接(这是一种很好的设计思想)
连接建立成功后,就会根据远程服务器的SID来创建并启动相应的消息发送器SendWorker和消息接受器RecvWorker
6.3.6 消息接收与发送
服务器上每个远程服务器都有其对应的消息发送器SendWorker、消息发送队列和消息接受器RecvWorker、消息接收队列
实现细节:发送消息时,顺便将消息放入LastMessageSent,作为最近发送过的消息;当针对当前远程服务器的消息发送队列为空时,且需要发消息,则从LastMessageSent中取出一个最近发送过的消息来进行发送
此细节解决的一类分布式问题:接收方没有正确处理消息,会要求重传,就是通过LastMessageSent实现的
6.3.7 FastLeaderElection:选举算法的核心部分
概念:
选票管理过程中相关组件之间的协作关系:
算法流程图和文字详解:
细节: