【闲聊杂谈】Zookeeper中的ZAB协议

1、Zookeeper ZAB 有主

上一篇中我们详细讲解了Paxos算法,而在Zookeeper中基于Paxos算法做了一个更简单的实现——ZAB(Zookeeper Atomic Broadcast)协议,可以认为是Paxos算法的一个精简版,更容易实现数据在分布式情况下的同步。

什么叫 Atomic ?Atomic 的意思是——原子,指的是没有中间状态,要么全部成功,要么全部失败,没有中间模棱两可的状态。

什么叫 Broadcast ?Broadcast 的意思是——广播,意味着这个集群里面是分布式多节点,并且在这个集群中广播不代表全部知道(比如像UDP协议走的就是广播协议,它不能确定对方每个人都收到)。

假设在一个Zookeeper集群中有1台leader和2台follower:

① 一个客户端对一台follower发起了一个写操作创建一个节点;

② follower将这个写请求转发给leader进行处理;

③ leader收到写请求,创建一个cZxid:1

④ leader通过广播告诉所有的follower将这个写请求创建日志记录

    4.1)Zookeeper的数据保存在内存中,但是日志记录却是在磁盘中。所以这一步触发的是在磁  盘中写入日志记录,而并没有在内存中创建出节点;

    4.2)在这一步的过程当中,leader使用了队列。在分布式情况下,任何节点之间的通信都有可能成功,可能失败,可能网络延迟等,所以引入了队列的机制。在leader当中对连接的每一个follower都维护了一个发送队列, leader所广播的每一步操作都放入这个队列中。

⑤ 其中一台follower在收到leader广播之后,会回复leader说知道了,在收到这个明确的回复之后,加上leader自己本身的这一票,也就是说在3台集群中已经有2台达成一致,满足过半通过;

⑥  leader再次通过队列广播follower开始真正在内存中创建节点;

⑦ follower创建完节点以后,会最终给leader回复一个OK,说明已经节点创建成功。

在上述的过程中,虽然只有一台follower给leader回复,另外一台follower可能因为网络延迟的原因没有给leader明确的回复,但是只要达成过半通过后leader广播给所有follower的队列中的命令是一样的。也就是说即便没有回复leader的那个follower,只要将队列中的消息按照顺序消费完,最终它的数据和别人一模一样,从而达成最终一致性。

上述全部完成以后,最终给客户端返回OK。

2、Zookeeper ZAB 选主

上一篇中在介绍Paxos算法的时候,我说leader的选举比较麻烦一两句话说不清楚,现在我们来好好唠一唠这个leader是如何选取出来的。

leader的选举一般来说分为两个场景:

① 集群第1次启动的时候,没有leader需要选出一个leader;

② 集群重启的时候或者leader宕机以后,需要重新选出一个leader。

之前在安装Zookeeper的时候,给每一个Zookeeper的实例都有创建一个myid; leader在每一次进行数据写入的时候,都会发起一个cZxid。基于这些已有的条件之后,我们先来想一想,当从一个集群之中要想选出一个leader的话,这个leader需要满足哪些条件?

首先,当选leader的这个实例必须是数据最全的:针对cZxid这个维度,也就是cZxid号最高;其次,无果这个集群网络非常好,每一个实力之间的通讯都非常的麻利,所有人的数据都是一样的全,那这个时候选leader就是论资排辈,也就是myid号最高。

假设在一个Zookeeper集群中:第一次启动集群,还没有leader

第一台:myid - 1,cZxid - 0

第二台:myid - 2,cZxid - 0

第三台:myid - 3,cZxid - 0

第四台:myid - 4,cZxid - 0

当你启动这个集群的时候,肯定是一台机器一台机器的去启动。而在启动第1台和第2台的时候,只有两台建立连接,但是两台各自为阵,所以没有办法选出一个leader。当启动第3台的时候,有三台两两连接,那么这个时候就已经可以产生过半通过了,此时大家的cZxid都是0,那么就看myid,谁的myid最大谁就是leader。这就是第1个场景:在集群第1次启动的时候选出一个leader的过程。

相比较于第1个场景leader的选举,在第2个场景中集群重启或者leader宕机以后,再次选出新的leader就会比较复杂一点。

假设还是那个Zookeeper集群中:第四台是leader

第一台:myid - 1,cZxid - 8

第二台:myid - 2,cZxid - 8

第三台:myid - 3,cZxid - 7

第四台:myid - 4,cZxid - 8

那么这个集群现在遇到这么一个场景:第1台、第2台的cZxid和leader一样,第3台还没有达成最终一致性的时候,leader宕机了,那么leader宕机以后对于每个follower维护的队列就没有了,第3台永远存活在低版本的cZxid中(其它都是8,只有3是7)。

而恰巧第3台最先发现leader宕机,于是第3台立马先投自己一票,然后再将自己的myid和cZxid发送给第1台和第2台。

第1台和第2台收到第3台发过来的消息,然后和自己的myid和cZxid比较,发现cZxid没自己的大,废止对第3台的投票,并且通过广播将自己的cZxid返回给第3台,告诉第3台说你不行让我来。也就是说第1台和第2台都会被动触发发起对自己的投票,并广播出去让别人为自己投票。

当第1台收到第2台的广播,同样的也会和之前一样去比较myid和cZxid,发现你的cZxid和我的cZxid一样,但是你的myid比我大,那么第1台就会废弃之前自己对自己的投票,并且给第2台投一票。同样的当第2台接收到第1台的广播的时候,也会去比较myid和cZxid,发现你的cZxid和我的cZxid一样大,但是你的myid没有我的myid大,就会继续保持自己对自己的投票。所以很快所有的follower都会给第2台投票,第二台立马就会变成leader。

所以在Zookeeper的集群中,其实任何一个follower发现leader宕机以后无论是谁发现的也好,无论发起的这台机器的cZxid是否足够高也好,只要发现了就会发起投票,这样的设计确保了在足够短的时间内发现leader宕机并且发起投票。就算发起这个投票的机器本身cZxid不够高也没有关系,如果你不够格做leader,就会引发另外够格的机器发起自己的投票,这就是Zookeeper集群可以在不到200毫秒的时间内选出一个leader的原因。

上一篇:1.zookeeper简介


下一篇:Zookeeper安装