最初了解它是在研究生期间,搭建过Hadoop集群,它用于为分布式集群提供一致性服务。它的核心是:类似树形文件系统、通知机制。
下面先介绍几个小概念。
节点类型从两个维度可以划分为4种,分别是:临时/持久,有序/无序
持久节点:(默认创建的就是持久节点)该数据节点被创建后,就会一直存在于zookeeper服务器上,直到有删除操作来主动删除这个节点。
临时节点:临时节点的生命周期和客户端会话绑定在一起,客户端会话session失效,则这个节点就会被自动清除
有序:(额外的特性)在ZK中,每个父节点会为它的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序(即,节点名后边会追加一个由父节点维护的自增整型数字)。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。
☕️ 说明:这4中节点一定要深入理解,后面的分布式锁会使用到!
客户端:client,开发时,我们使用的就是客户端,向服务端发送MDL请求
服务端:包含3个角色,分别是leader、follower、observer
leader:集群必须有领导者,才能提供服务;它用于处理事务事件(更新写)
follower:同步leader数据到自己节点,提供非事务事件(读);参与投票选主
observer:与follower一样,唯一的不同是不参与投票选主,它的出现是为了提高集群读性能
集群中所有的节点都共享的配置信息,该配置文件会改变(如,集群各个节点的状态信息)。实现思路:在ZK上创建配置信息节点,并让各个主机监控节点事件;当节点配置信息发生修改时,会触发回调函数,所有的节点同步更新信息。
采用临时节点特性。实现思路:节点上线时,与ZK建立连接并创建临时节点;当节点下线时,连接会断开,此时临时节点会被自动释放。
采用经典的观察者模式,与Redis/ZeroMq的发布订阅模式原理类似。实现思路与2.2中的很像,2.4中的临时节点+分布式锁也应用到
客户端加锁成功条件:客户端A创建了zknode,那么,锁就被客户端持有。
将zookeeper上的一个znode看作是一把锁,通过create_znode的方式来实现加锁,即:所有客户端都只创建 /distribute_lock节点,最先成功创建该节点的那个客户端就会拥有了这把锁。(再次期间,别的客户端想加锁,就会失败)。
客户端处理完后,要删除掉自己创建的/distribute_lock节点,即释放出锁。(之后,其他客户端可以加锁了)
使用套路
client_uuid = zk.lock(); // 加锁时,返回uuid zk.unlock(client_uuid); // 解锁时,通过该client_uuid判断,防止解开别的client的锁,造成锁失效
初始时,ZK上目录/distribute_lock已经预先存在,所有客户端在它下面创建一堆持久节点,它们是有序的;
为了避免“羊群”,每个节点都只会监控第一个比它大的节点。
编号最小的会获得锁,处理完业务逻辑后,删除节点(相当于解锁)。此时,会触发监听该节点的,触发回调函数,即下一个编号较小的节点会加锁失败。
Zookeeper中的过半原则
选举票数过半的主机,成为master
两阶段,follower执行事务成功的ACK次数过半,leader才会下发Commit信号
集群存活主机数,必须过半,才能提供服务
ZAB一致性协议,主要包含两个方面,分别是:
选举阶段
数据同步阶段
①集群刚启动时 ②leader宕机 ③follower下线,使得leader的follower数不过半
选谁的核心原则:就是谁最新,就选谁。
先介绍几个概念:epoch、ZXID、myid
epoch:译为“时代/纪元”。每个次leader在变更/切换时,epoch都会+1,标志一个leader所处的版本
ZXID:事务ID,ZK上的节点变化时,都是客户端发了事务操作导致的,对每一个事务操作,都用ZXID记录,每次发生事务,ZXID就+1
myid:服务端的配置信息,里面记录了各个ZK server的序号,一般,序号越大的server,越晚加入集群,它是最新的
cd /tmp/zookeeper mkdir {zoo1,zoo2,zoo3} echo 1 > zoo1/myid echo 2 > zoo2/myid echo 3 > zoo3/myid
选举原则
先选择epoch最大的
epoch相等时,选择ZXID最大的
epoch、ZXID相等时,选择myid最大的
生成选票:每个ZK server都采用上面的选举原则进行投票,一般都是先选择自己
更新选票:然后将自己的选票与其他ZK server交换,通过选举原则更新选票
确立leader:在更新过程中,如果发现某个ZK server的选票数过半,则该ZK server就成为leader
数据同步采用的是一致性协议2PC,过程如下
leader向follower发送事务执行指令,等待follower执行事务
leader收集follower执行结果(follower将返回是否执行成功的标记):如果半数follower执行成功,leader就会发送commit事务的指令
一些小小的知识点
follower执行成功,返回ACK的条件
答:当follower写完事务日志后,将认为数据已经同步好了,就直接返回执行成功的ACK,无需等待所有数据都落盘
节省资源,过半原则,5个机器,(过半,3)只允许挂2个机器;6个机器(过半,4),也只允许挂掉2个机器。因为5个机器和6个机器的分区容错性一致,所以,选奇数。
答:防止脑裂 原因:两个机房通过一根网线相连接,每个机房6个主机,当断网后,各个机房主机都存活(符合半数存活,ZK可用原则),两个主机会各自选出leader,此时集群会出现双主,发生脑裂
2N+1 = 3
官方声明:一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,该事件将不会继续被监听。 为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,给网络和服务器造成很大压力。
读写分离特性,即:在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行 leader 选举。