Zookeeper的选举机制和同步机制超详细讲解,面试经常问到!
前言
zookeeper相信大家都不陌生,很多分布式中间件都利用zk来提供分布式一致性协调的特性。dubbo官方推荐使用zk作为注册中心,zk也是hadoop和Hbase的重要组件。其他知名的开源中间件中也都出现了zk的身影。
有很多童鞋认识zk很久了,知道其基本理念,知道如何使用。但当面试时问到集群zk之间的选举和数据同步机制时,就陷入了盲区。
其实很多的分布式中间件的选举和同步,都和zk有异曲同工之妙。这篇文章我就来重点聊下关于zk集群之间的选举和同步机制。
ZK集群的部署
首先我们来看下半数运行机制:
集群至少需要三台服务器,且官方文档强烈建议使用奇数个服务器,因为zookeeper是通过判断大多数节点的的存活来判断整个服务集群是否可用的,比如3个节点,它的一半是1.5,向上取整就是2。挂掉了2个就是表示整个集群挂掉。而用偶数4个的话,挂掉2个也表示不是大部分存活,因此也会挂掉。所以用4台服务器的话 ,从使用资源上来说,并不划算。
配置语法:
server.<节点ID>=<IP>:<数据同步端口>:<选举端口>
- 节点ID:为1到125之间的数字,写到对应服务节点的{dataDir}/myid文件中。
- IP地址:节点的远程IP地址,可以相同,生产环境建议用不同的机器,否则无法达到容错的目的。
- 数据同步端口:主从同步时数据复制端口。
- 选举端口:主从节点选举端口。
假设现在有3个zookeeper节点,我们要为其编写config配置,也要编写3份,分别放在不同的服务器上,其配置如下:
initLimit=10
syncLimit=5
dataDir=/data/zk_data
clientPort=2181
# 集群配置
server.1=192.168.1.1:2888:3888
server.2=192.168.1.2:2888:3888
server.3=192.168.1.3:2888:3888
其中dataDir参数指定的是一个目录,用来存放zk的数据,里面有个文件myid,3台机器上myid文件里面分别存放1,2,3。对应各自节点ID。
配置好3个配置文件后,分别启动,这样我们一个3个节点的集群zookeeper就搭建好了。
./bin/zkServer.sh start conf/zoo.cfg
ZK集群中的角色
zookeeper集群中公共有三种角色,分别是leader,follower,observer。
| 角色 | 描述 |
|---|---|
| leader | 主节点,又名领导者。用于写入数据,通过选举产生,如果宕机将会选举新的主节点。 |
| follower | 子节点,又名追随者。用于实现数据的读取。同时他也是主节点的备选节点,并拥有投票权。 |
| observer | 次级子节点,又名观察者。用于读取数据,与follower区别在于没有投票权,不能被选为主节点。并且在计算集群可用状态时不会将observer计算入内。 |
关于observer的配置:
只要在集群配置中加上observer后缀即可,示例如下:
server.3=127.0.0.1:2883:3883:observer
其中leader只有一个,剩下的都是follower和observer,但是我们一般生产上不会配置observer,因为observer并没有选举权,可以理解为observer是一个临时工,不是正式员工,没法获得晋升。除此之外,它和follower的功能是一样的。
什么时候需要用到observer呢,因为zk一般读的请求会大于写。当整个集群压力过大时,我们可以增加几个临时工observer来获得性能的提升。在不需要的时候的时候,可以随时撤掉observer。
zk进行连接时,一般我们都会把zk所有的节点都配置上去,用逗号分隔。其实连接集群中的任意一个或者多个都是可以的。只是如果只连一个节点,当这个节点宕机的时候,我们就断开了连接。所以还是推荐配置多个节点进行连接。
如何查看ZK集群中的角色
我们可以利用以下命令来查看zk集群中的角色
./bin/zkServer.sh status conf/zoo.cfg
我在自己机器上搭建了3个节点的伪集群(共用一台机器),配置文件分别命名为zoo1.cfg,zoo2.cfg,zoo3.cfg。使用以上命令查看的结果为:

可以看到,其中节点2为leader,其他的为follower。但是如果你按照zoo1.cfg,zoo2.cfg,zoo3.cfg的顺序启动,无论你启动多少遍,节点2总是leader,而这时如果把节点2关掉,进行查看角色,发现节点3成了leader。

以上这些现象都和zookeeper的选举机制有关
ZK集群的选举机制
我们就拿3个节点的zk作一个简单选举的说明

zk会进行多轮的投票,直到某一个节点的票数大于或等于半数以上,在3个节点中,总共会进行2轮的投票:
- 第一轮,每个节点启动时投票给自己,那这样zk1,zk2,zk3各有一票。
- 第二轮,每个节点投票给大于自己myid,那这样zk2启动时又获得一票。加上自己给自己投的那一票。总共有2票。2票大于了当前节点总数的半数,所以投票终止。zk2当选leader。
有的童鞋会问,zk3呢,因为zk2已经当选了,投票终止了。所以zk2也不会投票给zk3了。
当然这是一个比较简单版的选举,其实真正的选举还要比较zxid,这个后面会讲到。
zk选举什么时候会被触发呢?一是启动时会被触发,二是leader宕机时会被触发。上面的例子中,如果节点2宕机,根据规则,那获得leader的就应该是zk3了。
ZK集群的数据同步机制
zookeeper的数据同步是为了保证每个节点的数据一致性,大致分为2个流程,一个是正常的客户端数据提交流程,二是集群中某个节点宕机后数据恢复流程。
正常客户端数据提交流程
客户端写入数据提交流程大致为:leader接受到客户端的写请求,然后同步给各个子节点:

但是有童鞋就产生疑惑了,客户端一般连接的是所有节点,客户端并不知道哪个是leader呀。
的确,客户端会和所有的节点建立链接,并且发起写入请求是挨个遍历节点进行的,比如第一次是节点1,第二次是节点2。以此类推。
如果客户端正好链接的节点的角色是leader,那就按照上面的流程走。那如果链接的节点不是leader,是follower呢,则有以下流程:

如果Client选择链接的节点是Follower的话,这个Follower会把请求转给当前Leader,然后Leader会走蓝色的线把请求广播给所有的Follower,每个节点同步完数据后会走绿色的线告诉Leader数据已经同步完成(但是还未提交),当Leader收到半数以上的节点ACK确认消息后,那么Leader就认为这个数据可以提交了,会广播给所有的Follower节点,所有的节点就可以提交数据。整个同步工作就结束了。
那我们再来说说节点宕机后的数据同步流程
当zookeeper集群中的Leader宕机后,会触发新的选举,选举期间,整个集群是没法对外提供服务的。直到选出新的Leader之后,才能重新提供服务。
我们重新回到3个节点的例子,zk1,zk2,zk3,其中z2为Leader,z1,z3为Follower,假设zk2宕机后,触发了重新选举,按照选举规则,z3当选Leader。这时整个集群只整下z1和z3,如果这时整个集群又创建了一个节点数据,接着z2重启。这时z2的数据肯定比z1和z3要旧,那这时该如何同步数据呢。
zookeeper是通过ZXID事务ID来确认的,ZXID是一个长度为64位的数字,其中低32位是按照数字来递增,任何数据的变更都会导致低32位数字简单加1。高32位是leader周期编号,每当选举出一个新的Leader时,新的Leader就从本地事务日志中取出ZXID,然后解析出高32位的周期编号,进行加1,再将低32位的全部设置为0。这样就保证了每次选举新的Leader后,保证了ZXID的唯一性而且是保证递增的。
查看某个数据节点的ZXID的命令为:
先进入zk client命令行
./bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
stat加上数据节点名称
stat /test
执行结果为:

可以看到,有3个ZXID,这3个ZXID各自代表:
cZxid:该节点创建时的事务ID
mZxid:该节点最近一次更新时的事务ID
pZxid:该节点的子节点的最新一次创建/更新/删除的事务ID
查看节点最新ZXID的命令为:
echo stat|nc 127.0.0.1 2181
这个命令需提前在cfg文件后追加:4lw.commands.whitelist=*,然后重启

这里的ZXID就是当前节点最后一次事务的ID。
如果整个集群数据为一致的,那么所有节点的ZXID应该一样。所以zookeeper就通过这个有序的ZXID来确保各个节点之间的数据的一致性,带着之前的问题,如果Leader宕机之后,再重启后,会去和目前的Leader去比较最新的ZXID,如果节点的ZXID比最新Leader里的ZXID要小,那么就会去同步数据。
再看ZK中的选举
我们带着ZXID的概念再来看ZK中的选举机制。
假设还是有一个3个节点的集群,zk2为Leader,这时候如果zk2挂了。zk3当选Leader,zk1为Follower。这时候如果更新集群中的一个数据。然后把zk1和zk3都关闭。然后挨个再重启zk1,zk2,zk3。这时候启动后,zk2还能当选为Leader吗?
其实这个问题,换句话说就是:在挨个启动zk节点的时候,zk1和zk3的数据为最新,而zk2的数据不是最新的,按照之前的选举规则的话,zk2是否能顺利当选Leader?
答案为否,最后当选的为zk1。
这是为什么呢。
因为zk2的最新ZXID已经不是最新了,zk的选举过程会优先考虑ZXID大的节点。这时ZXID最大的有zk1和zk3,选举只会在这2个节点中产生,根据之前说的选举规则。在第一轮投票的时候,zk1只要获得1票,就能达到半数了,就能顺利当选为Leader了。
最后
其实zk的选举和同步并不复杂,如果能试着在本地去搭建3个节点的伪集群,去试着跑一下上面的案例。应该就能明白整个过程。zk作为老牌的一致性协调中间件,也是诸多面试的频次很高的问点。如果你能理解本篇的核心内容,再次碰到这类问题的时候,这将不会是你的盲区。最后,喜欢本篇内容的朋友希望点赞,关注,转发。

Zookeeper的选举机制和同步机制超详细讲解,面试经常问到!的更多相关文章
- Java集合框架总结—超详细-适合面试
Java集合框架总结—超详细-适合面试 一.精简: A.概念汇总 1.Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口, ...
- 内核同步机制-RCU同步机制
转自:https://blog.csdn.net/nevil/article/details/7718375 转自http://www.360doc.com/content/09/0805/00/36 ...
- Keras代码超详细讲解LSTM实现细节
1.首先我们了解一下keras中的Embedding层:from keras.layers.embeddings import Embedding: Embedding参数如下: 输入尺寸:(batc ...
- java 异步机制与同步机制的区别
所谓异步输入输出机制,是指在进行输入输出处理时,不必等到输入输出处理完毕才返回.所以异步的同义语是非阻塞(None Blocking). 网上有很多网友用很通俗的比喻 把同步和异步讲解的很透彻 转过 ...
- nginx源代码分析--进程间通信机制 & 同步机制
Nginx源代码分析-进程间通信机制 从nginx的进程模型能够知道.master进程和worker进程须要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号, ...
- js-异步机制与同步机制
Javascript的优势之一是其如何处理异步代码.异步代码会被放入一个事件队列,等到所有其他代码执行后才进行,而不会阻塞线程 1 理解异步代码: 1.1 JavaScript最基础的异步函数是set ...
- RAID技术超详细讲解
RAID 技术是一种多磁盘技术,面对数据的各方面有着两面性的影响,整体来说优点大于缺点的,下面我将详细介绍一下 RAID ,简称磁盘阵列技术. 一.RAID 概述 1988 年美国加州大学伯克利分校的 ...
- Python与Javascript相互调用超详细讲解(2022年1月最新)(一)基本原理 Part 1 - 通过子进程和进程间通信(IPC)
TL; DR 适用于: python和javascript的runtime(基本特指cpython[不是cython!]和Node.js)都装好了 副语言用了一些复杂的包(例如python用了nump ...
- 前端模块化IIFE,commonjs,AMD,UMD,ES6 Module规范超详细讲解
目录 为什么前端需要模块化 什么是模块 是什么IIFE 举个栗子 模块化标准 Commonjs 特征 IIFE中的例子用commonjs实现 AMD和RequireJS 如何定义一个模块 如何在入口文 ...
随机推荐
- 深入浅出Mybatis系列(一)---Mybatis简介
1.什么是MyBatis? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且 ...
- JavaWeb学习总结——使用Session防止表单重复提交
在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...
- 关于Java for循环的注意点
1 import java.util.ArrayList; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 ...
- JavaWeb之HttpSession
时间:2016-11-17 22:33 --HttpSession一.HttpSession概述 1.HttpSession是由JavaWeb提供的,用来进行会话跟踪的类. 2.sessi ...
- Android WorkManager 定时任务
App有时可能需要定期运行某些工作.例如,可能要定期备份数据.上传信息到服务器,定期获取新的内容等等. 在app运行期间,我们使用Handler也可以完成定期的功能.在这里我们介绍WorkManage ...
- springcloud<seata配置文件解释及其说明>
出现如下错误时: Could not found property service.disableGlobalTransaction, try to use default value instead ...
- MySQL密码重置方法
MySQL数据库的安装和配置,配置Mysql按照bin目录到Path中 使用命令行窗口连接MYSQL数据库:mysql –u用户名 –p密码 对于密码的重置有以下两种方法(卸载重新安装当然也可以): ...
- Python安装环境配置和多版本共存
Python安装环境配置和多版本共存 1.环境变量配置: (1) 右键点击"计算机",然后点击"属性" (2) 然后点击"高级系统设置" ( ...
- redis未授权getshell的4种方式
前言 redis未授权漏洞或弱口令一直是很有用的渗透突破口,最近正好闲的无事就拿redis来测试一些,做一个简单的收集,方便自己日后的回顾. 漏洞描述 Redis 默认情况下,会绑定在 0.0.0.0 ...
- 操作系统IO之零拷贝技术
磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝.直接 I/O.异步 I/O 等等,这些优化的目的就是为了提高系统的吞吐量,另外操作系统 ...