ZooKeeper系列:Leader选举
目录
前置
一、不同场景下的选举
1、服务启动时期的Leader选举
2、服务器运行期间的选举
二、算法细节
1、投票信息的数据结构
2、网络IO:QuorumCnxManager
2.1 消息队列
2.2 连接建立
2.3 消息接收和发送
三、算法核心
1、基本概念
2、选票管理
3、选举流程
前置
myid:机器在集群中的编号
SID:Server ID,是一个数字,和myid一致,标识集群中一台机器的唯一标识。
ZXID:事务的编号
一、不同场景下的选举
当一台机器加入到集群,该机器会发起Leader选举。如果集群中已经存在Leader服务器,则该机器会被告知Leader信息。该机器会退出Leader选举状态,连接Leader并和同步状态;如果此时集群中不存在Leader,则会进行Leader选举。
从3.4.0以后,ZooKeeper只支持FastLeaderElection选举算法。
1、服务启动时期的Leader选举
主要步骤如下:
1、初始投票
初始情况,每个机器并不了解其他机器的信息,所以每个机器都会将自己作为候选人发起投票。投票的内容为:(myid, ZXID)。每个机器都会将自己的投票情况发送给集群中的其他所有集群。
2、接收投票
机器在接收到其他机器的投票后,会首先检查该投票的有效性:轮次是否正确(是否是本轮的投票),是否来自LOOKING状态的机器。
3、处理投票
如果接收到的投票是有效的,那么机器会将该投票和自己的投票进行对比:
1)对比ZXID,选择ZXID大的服务器作为Leader;
2)如果ZXID相同,对比myid,选择myid大的服务器作为Leader。
因为是刚刚启动,所以此时ZXID都是相同的,实际上就是在比较myid。如果接收到的投票在对比中获胜,就更新自己的投票为该投票信息,并重新发送更新后的投票信息。
4、统计投票
每次投票后,每个服务器都会对集群中所有的投票情况进行统计。如果统计到此时有过半的机器接收到相同的投票信息,就会认为被过半机器选举的服务器是Leader机器。
5、变更状态
一旦确定了服务器状态,每个服务器就会更新自己的状态:Follower更新为FOLLOWING,Leader更新为LEADING。
2、服务器运行期间的选举
如果Leader服务器因为服务崩溃、关闭、重启、网络问题等原因,导致和集群中过半机器失去联系,此时这个集群将暂时对外停止写服务,并重新进入Leader选举状态。
此时的Leader选举的步骤:
1、变更状态
非Observer机器都会将自己的状态从FOLLOWING变更为LOOKING,进入选举流程。
2、初始投票
跟服务启动时间的Leader选举相同。此时每个机器都会将自己作为候选人进行投票,生成投票信息(myid, ZXID)并通知其他机器。
3、接收投票
跟服务启动时间的Leader选举相同。接收并校验投票的有效性。
4、处理投票
跟服务启动时间的Leader选举相同。对比接收到的投票和自己的投票,如果需要就更新并重新发松投票信息。
5、统计投票
跟服务启动时间的Leader选举相同。统计集群中的所有集群的投票信息,判断是否已经选出Leader。
6、变更投票
跟服务启动时间的Leader选举相同。Follower更新为FOLLOWING,Leader更新为LEADING。
二、算法细节
FastLeaderElection算法并不复杂,但是在实现过程中还是有一些细节方面的问题。
1、投票信息的数据结构
org.apache.zookeeper.server.quorum.Vote类用来表示投票信息。主要成员属性:
属性 |
说明 |
id |
被推荐的Leader的SID |
zxid |
被推举Leader的ZXID |
electionEpoch |
逻辑时钟,用来判断是不是在同一个投票轮次;发起新一轮投票时+1 |
peerEpoch |
被推举的Leader的epoch,即zxid的高32位,每次Leader选举完成后递增 |
state |
当前服务器的状态,枚举:LOOKING, FOLLOWING, LEADING, OBSERVING |
2、网络IO:QuorumCnxManager
QuorumCnxManager用来负责服务器之间底层Leader选举过程中的通信。
2.1 消息队列
QuorumCnxManager中维护了一系列的队列,用来存储消息的发送器、待发送的消息、最后一次发送的消息、以及接收到的消息。
队列如下:
类型 |
名称 |
说明 |
ConcurrentHashMap<Long, SendWorker> |
senderWorkerMap |
key:其他服务的SID;value:消息的发送器,Thread的从超类 |
ConcurrentHashMap<Long, ArrayBlockingQueue<ByteBuffer>> |
queueSendMap |
key:其他服务的SID;value:待发送消息的队列 |
ConcurrentHashMap<Long, ByteBuffer> |
lastMessageSent |
key:其他服务的SID;value:最后一次发送的消息 |
ArrayBlockingQueue<Message> |
recvQueue |
接收到的消息的队列 |
2.2 连接建立
1)连接管理
为了保证能进行服务启动时期的投票,服务在启动的时候就会启动QuorumCnxManager,在服务器两两之间建立连接。在QuorumCnxManager的启动过程中创建一个ServerSocket来监听Leader选举端口。
2)处理逻辑
这个监听是通过Listener来实现的,这是Thread的超类,在run方法中通过两层while循环,创建ServerSock而并不断的监听端口,一旦接收到消息,就会交给receiveConnection方法进行处理。
3)避免重复
为了避免两台机器重复建立连接,zk要求只能SID大的服务主动发起连接建立。在处理连接的方法receiveConnection中,会对比目标服务和自己的SID,判断是否接受连接请求。
4)消息发送
连接建立后,会通过SID来管理消息和消息发送器,参考上面的消息队列。
2.3 消息接收和发送
1)消息接收
消息接收通过RecvWorker来实现。zk会为每个远程服务器分配一个单独的RecvWorker,每个RecvWorker只需要不断的从这个TCP连接中读取消息,并保存到RecvQueue中。
2)消息发送
消息发送通过SendWorker来实现。zk会为每个远程服务器分配一个单独的SendWorker,这个SendWorker只需要不断的根据SID从queueSendMap中取出消息并发送,同时将这条消息根据SID放入lastMessageSent中。
需要注意的是,如果待发送消息队列空了,此时SendWorker会从lastMessageSent中取出最后一条消息,然后不断重复发送。这是为了避免连接关闭导致的最后一条消息没有被正确处理的情况。当然,接收端也会正确处理重复消息。
发送端发送最近一条消息(SendWorker的run方法):
三、算法核心
1、基本概念
外部投票:其他服务器发来的投票
内部投票:当前服务器自身的投票
选举轮次:逻辑时钟,即本次Leader选举中的投票轮次
PK:对比内部投票和外部投票,看是否要变更内部投票
2、选票管理
zk通过QuorumCnxManager管理服务器之间的投票发送和接收。FastLeaderElection中定义一些组件,用于调用QuorumCnxManager来实现投票的管理:
sendqueue:选票发送队列,保存待发送的队列;
recvqueue:选票接收队列。保存接收到的外部投票;
WorkerSender:选票发送器。不断的从sendqueue中取出投票信息,并发送给QuorumCnxManager,存储到queueSendMap。
WorkerReceiver:选票接收器。不断从QuorumCnxManager中取出外部投票,并转换成选票的类型Message,保存到revcQueue。
这里需要注意的是,对对于选票接收器,接收到的选票轮次低于自身的轮次,则忽略该投票, 并将内部投票发出去;如果自身并不在LOOKING状态,就忽略该投票,并以投票的形式发送Leader的信息;如果该投票来自于Observer,则直接忽略该信息,并发送内部投票。
选票管理的过程:
3、选举流程
选举流程通过FastLeaderElection中的lookForLeader方法实现,这也是FastLeaderElection算法的核心。
1、自增选举轮次
在FastLeaderElection实现中,有一个logicalclock属性,用于标识当前Leader的选举轮次,ZooKeeper规定了所有有效的投票都必须在同一轮次中。ZooKeeper在开始新一轮的投票时,会首先对logicalclock进行自增操作。
2、初始化选票
在开始进行新一轮的投票之前,每个服务器都会首先初始化自己的选票。在初始阶段,每个服务器都会推荐自己成为Leader。初始化投票如下:
属性 |
值 |
id |
当前服务器自身的SID |
zxid |
当前服务器最新的ZXID |
electionEpoch |
当前服务器的选举轮次 |
peerEpoch |
被推荐的服务器的选举轮次(当前服务器) |
state |
LOOKING |
3、发送初始化选票
在完成选票的初始化后,服务器就会发起第一次投票。ZooKeeper会将刚刚初始化好的选票放入sendqueue队列中,由发送器WorkerSender负责发送出去。
4、接收外部投票
每台服务器都会不断地从recvqueue队列中获取外部投票。如果服务器发现无法获取到任何外部投票,就会立即确认自己是否和集群中其他服务器保持着有效连接。如果发现没有建立连接,那么就会马上建立连接;如果已经建立了连接,那么就再次发送自己当前的内部投票。
5、判断选举轮次
当发送完初始化选票之后,接下来就要开始处理外部投票了。在处理外部投票的时候,会根据选举轮次来进行不同的处理。
1)外部投票的选举轮次大于内部投票
如果服务器发现自己的选举轮次已经落后于该外部投票对应服务器的选举轮次,那么就会立即更新自己的选举轮次(logicalclock),并且清空所有已经收到的投票,然后使用初始化的投票来进行PK以确定是否变更内部投票,最终再将内部投票发送出去。
2)外部投票的选举轮次小于内部投票
如果接收到的选票的选举轮次落后于服务器自身的,那么ZooKeeper就会直接忽略该外部投票,不做任何处理,并返回步骤4。
3)外部投票的选举轮次和内部投票一致
这是绝大多数下的情况。此时会开启选票PK。
6、选票PK
选票PK的目的是为了确定当前服务器是否需要变更投票,主要从选举轮次、ZXID和SID三个因素来考虑,依次判断,符合任意一个条件就需要进行投票变更。具体如下:
1)如果外部投票被推举Leader的选举轮次大于内部投票,则进行投票变更;
2)如果选举轮次一致,就对比两者的ZXID。如果外部投票的ZXID大于内部投票,则进行投票变更;
3)如果两者的ZXID一致,就对比两者的SID。如果外部投票的SID大于内部投票,则进行投票变更。
7、变更投票
通过选票PK后,如果确定了外部投票优于内部投票,那么就进行投票变更,使用外部投票的选票信息来覆盖内部投票。变更完成后,再次将这个变更后的内部投票发送出去。
8、选票归档
无论是否进行了投票变更,都会将刚刚收到的外部投票放入选票集合recvset中进行归档。recvset用于记录当前服务器在本轮次的Leader选举中收到的所有外部投票。
9、统计投票
完成选票归档后,就可以开始统计投票。统计投票是为了统计集群中是否已经有过半的服务器认可了当前的内部投票。如果是,则终止投票;否则返回步骤4。
需要注意的是,当确认过半服务器认可投票后,仍然会等待一段时间,以判断是否有更优的投票。如果有,用更优投票替代当前统计结果。
10、更新服务器状态
统计投票后,如果确定可以终止投票,那么就开始更新服务器状态。服务器会首先判断当前被过半服务器认可的投票所对应的Leader服务器是否是自己,如果是自己的话,那么就会将自己的服务器状态更新为LEADING。如果自己不是被选举产生的Leader的话,那么就会根据具体情况来确定自己是FOLLOWING或是OBSERVING。
上述过程中,4~9是放在while循环中的,会经过多次循环,直到Leader选举产生。
ZooKeeper系列:Leader选举相关推荐
- 面试官:说一说Zookeeper中Leader选举机制
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,可以微信搜索[小奇JAVA面试]第一时间阅 ...
- 分布式开发必须了解的Zookeeper的Leader选举机制(源码解析)
分布式开发必须知道的Zookeeper知识及其的Leader选举机制(ZAB原子广播协议) ZooKeeper是Hadoop下的一个子项目,它是一个针对大型分布式系统的可靠协调系统,提供的功能包括 ...
- Zookeeper的Leader选举
简单理解Zookeeper的Leader选举 原文链接:简单理解Zookeeper的Leader选举_程裕强的博客-CSDN博客_zk的leader选举 Leader选举是保证分布式数据一致性的关键所 ...
- zookeeper的Leader选举机制详解
转载自:https://www.toutiao.com/i6701570306445672963/?tt_from=copy_link&utm_campaign=client_share&am ...
- Zookeeper之Leader选举源码分析
Zookeeper源码下载地址:https://github.com/apache/zookeeper 1.选举流程 Zookeeeper的Leader选举会分两个过程. 服务启动时的leader选举 ...
- Zookeeper的Leader选举-选举过程介绍比较清晰
http://www.cnblogs.com/leesf456/p/6107600.html 一.前言 前面学习了Zookeeper服务端的相关细节,其中对于集群启动而言,很重要的一部分就是Leade ...
- Zookeeper里Leader选举算法
ZooKeepe集群中的三种服务器角色:Leader.Follower.Observer,本文主要概述Leader选举算法相关的知识. 一.Zookeeper里三种角色 1.Leader:Leader ...
- zookeeper的leader选举机制
什么是zxid和myid? zxid: zookeeper为了保证数据的有序性,会给每一个写操作的数据,编写一个全局唯一的zxid. zxid是一个64位的数字:前32位会是由当前节点参与的选举次数决 ...
- 使用Zookeeper实现leader选举-Leader Latch
参与选举的所有节点,会创建一个顺序节点,其中最小的节点会设置为master节点, 没抢到Leader的节点都监听前一个节点的删除事件,在前一个节点删除后进行重新抢主,当master节点手动调用clos ...
- 使用Zookeeper实现leader选举
在分布式计算中,leader election是很重要的一个功能,这个选举过程是这样子的:指派一个进程作为组织者,将任务分发给各节点.在任务开始前,哪个节点都不知道谁是leader或者coordina ...
最新文章
- 查询数据库所有表、字段、触发器等
- php 单词替换,如何在PHP中替换字符串中的单词?
- cocos2d实现语音_Cocos2d-x 3.2 Lua示例CocosDenshionTest(音频测试)
- GDCM:VolumeSorter的测试程序
- linux与mysql_Linux与MySQL
- 23中设计模式之抽象工厂模式
- 抖音去水印解析网址入口_抖音去水印 视频去水印 小工具
- 上过云么?一行代码秒上云体验过么?
- 小米自然语言处理工程师招聘条件与自己的对应整理(第二次更新)
- Ubuntu20 运行不了网络助手NetAssist
- Windows 7下可用的“超级终端”——Hypertrm和SecureCRT
- MySQL的数据库导出命令
- android 视频缓存溢出导致视频黑屏,MediaMuxer+MediaCodec生成MP4视频黑屏
- c++实现远程开关机
- 如何将摄像机拍摄信号采集到直播软件
- ZJM与生日礼物【字典树】
- Android adb shell后面可用的常用命令详细列举
- 51单片机程序加密c语言,51单片机24C04密码锁(C程序+Proteus仿真)
- .NET 7 预览版 1 发布
- 3.10 杭电复试题2012
热门文章
- Java游戏开发超级玛丽总结_java超级玛丽游戏计算机(毕业设计)论文.doc
- 小觅摄像头 VINS-MONO安装
- 转载的硬件十万个为什么
- 1fichier.com-1TB免费FTP空间的使用
- 计算机革命的主角和英雄——十大超级老牌黑客
- 淘客基地淘客小程序系统更新至1.2.4 版本
- python 基于numpy的线性代数运算
- No module named libs.resources
- 大写的“人”——《杀死一只知更鸟》读后感范文4800字
- 资本运作/自我投资--哪项需要优先?