ZooKeeper学习---ZAB协议

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_34596644/article/details/78164694

前言:ZooKeeper是典型的分布式数据一致性解决方案,旨在将复杂、容易出错的分布式一致性服务封装起来,构成高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。基于CAP理论和BASE理论的支撑,在分布式系统中,我们经常需要对一致性和可用性做出权衡。那么ZooKeeper是通过什么策略来进行取舍权衡的呢?答案就是ZAB协议。


一、什么是ZAB协议?

ZAB协议(即ZooKeeper Atomic Broadcast,ZooKeeper原子消息广播协议)是一种分布式一致性协议,类似于2PC(二阶段提交协议)、3PC(三阶段提交协议)和Paxos,是对一致性和可用性权衡过后的一种事务处理思想。另外,ZAB协议是专门为ZooKeeper设计的一致性协议,并不像Paxos那样具有通用性。

二、ZAB协议的核心?

  ZAB协议的核心是定义了对于那些会改变ZooKeeper服务器数据状态的事务请求的处理方式。

  ZooKeeper服务器的角色分为三种:

  • Leader:全局唯一,负责协调整个ZooKeeper集群。
  • Follower:与Leader保持数据同步,并向ZooKeeper客户端提供读服务。
  • Observer:与Follower类似,但是Observer不参与Leader选举流程和“过半写”策略。

  具体的,ZooKeeper客户端的“读”请求可以从Leader/Follower/Observer服务器上读取。但是ZooKeeper客户端的“写”请求必须由Leader服务器协调处理(由Follower和Observer接收到的“写”请求同样会移交给Leader处理)。在Leader服务器上会为每一个Follower服务器分配一个单独的队列,它会将客户端“写”请求转换成一个事务Proposal(提议)并依次放入这些队列中,根据FIFO策略将Proposal移交给所有的Follower服务器。每一个Follower服务器在接收到这个事务Proposal之后,都会首先将其以事务日志形式写入磁盘,并在成功写入之后反馈服务器一个ACK响应,如果Follower不接受这个Proposal则直接不需要响应Leader。当Leader服务器接收到超过半数Follower的ACK相应后,就会广播一个Commit消息给所有的Follower服务器以通知其进行事务提交。同时Leader本身也会完成事务提交,每一个Follower接收到Commit消息后也会完成事务提交。这里相当于少数服从多数的原则。

三、ZAB协议的两种模式

ZAB协议工作时包含两种模式:崩溃恢复和消息广播。
   崩溃恢复:当这个服务框架在启动过程中,或是当Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入该模式,重新选举新的Leader服务器。
   消息广播:当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会进入该模式。

  •   消息广播模式下的工作流程:
针对于客户端的事务请求,Leader服务器会为其生成对应的事务Proposal和对应的事务全局单调递增的唯一ID(ZXID),然后将Proposal通过Leader上为Follower分配的队列发送给其他的机器,然后收集各个ZooKeeper服务器的投票情况,决定是否提交事务。这个过称类似于2PC,但没有2PC中的中断反馈,Leader外的服务器要么向Leader反馈可以执行事务的投票响应,要么直接不响应。也因为这个策略,Leader并不需要统计所有的选票,只需要得到过半ZooKeeper服务器的反馈就可以发出事务的提交指令了。如图:


--->>>崩溃恢复模式是针对消息广播模式下可能出现的数据一致性问题而设计的。所以在描述崩溃恢复模式之前,我们先来探讨一下消息广播中可能会出现的数据一致性问题。
这里笔者暂且将数据一致性问题分为两类进行讨论(ps:这两个分类的描述可能有点理解):
a.数据暂时的不一致。
b.数据永久的不一致。
前面我们提到,来自客户端的“写”请求是需要通过ZooKeeper集群中的Leader服务器进行协调的,而其他服务器是需要与Leader取得同步以保持其最新的数据副本。我们知道,这种同步必然是需要一定的时间的。假设两个客户端在这个同步的过程中同时请求获取某个数据节点上的数据,一个请求被路由至Leader服务器,另一个被路由至一个未同步完成的Follower服务器,那么就可能存在同一时间两个客户端从同一ZooKeeper集群中读取同一数据节点,数据却不一致的情况。但是这种数据不一致在完成Leader和Follower的同步之后却又会消失,因此笔者这里将它称为数据暂时的不一致。
数据永久的不一致指的是在Leader与Follower状态同步期间Leader服务器出现异常或是宕机,导致新的一轮Leader选举。Leader服务器需要保证自身正在同步的事务在新的Leader服务器诞生之后能够继续同步到所有的服务器。对于Leader服务器刚接收到但仍未开始同步流程的事务,在新的Leader服务器选举出来之后需要抛弃这个事务。否则,ZooKeeper上的数据也会出现不一致的状态,并且这种不一致是无法恢复的,笔者将其称为数据永久的不一致。
--->>>通过以上的分析,我们可以得到两个结论。
a.ZooKeeper并不能保持实时的数据一致性,但可以保证最终一致性和单调一致性。如有必要,ZooKeeper客户端依然可以通过相应的API接口强制获取到最新的数据。
b.ZooKeeper的崩溃恢复模式需要解决的是数据永久的不一致问题。ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有的服务器都提交;ZAB协议需要确保丢弃那些只在Leader服务器上被提交的事务。

  • 崩溃恢复模式下的工作流程:
针对上面分析中ZAB协议在崩溃恢复模式中需要解决的两个问题,ZAB协议在该模式下需要有这样一个Leader选举算法:能够确保提交已经被Leader提交的事务Proposal,同时丢弃已经被跳过的事务Proposal。为此,我们需要保证被选举为新Leader的服务器拥有集群中所有机器最高编号的事务Proposal(即ZXID最大),也即这个服务器已经提交了Leader崩溃前最后发布的事务Proposal。

--->>>有了这个思想之后,我们再来看看ZAB协议具体是如何解决上面两个可能出现的数据一致性问题的。
a.ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有的服务器都提交
完成新的Leader选举之后,因为新的Leader的ZXID最大,因此它的事务日志中必定有原Leader崩溃前提交的所有事务Proposal记录,接下来只需要将这些事务同步到其他服务器上即可。Leader服务器通过为Follower服务器分配的队列将那些没有被各Follower同步的事务逐个发送给Follower服务器,并在每一个Proposal之后紧接着发送一个Commit消息,表示这个事务已经被提交了。等到Follower将所有未同步的事务重新同步之后,Leader服务器才会将该Follower服务器加入到可用的Follower列表中。
b.ZAB协议需要确保丢弃那些只在Leader服务器上被提交的事务
ZooKeeper中的事务编号是用ZXID代表的,它是一个64位数字。低32位是一个简单递增的计数器,在一个Leader的领导周期中,这个计数器会依次递增。高32位则代表了Leader周期,每次重新选举Leader都会在当前周期上加一代表下个领导周期的开始,并将低32位重新置0。基于这样的策略,一个Leader崩溃后,重新选举的Leader的周期计数会加一(即ZXID会变大),假如某个时刻崩溃的Leader在新Leader选举后又恢复了正常,这时它是无法成为Leader的,因为它的最大事务Proposal编号ZXID必然比当前的Leader小(因为它还处于上一个周期),所以它会成为Follower加入到ZooKeeper集群中。当Leader检测到新的Follower加入集群后,首先需要进行状态同步,Leader会检测到这个Follower上有一个上个周期没被提交的事务Proposal,Leader会要求该Follower忽略这个事务Proposal,并回退到一个确实被提交的事务Proposal,重新开始事务的同步。同步完成后,Leader服务器才会将该Follower服务器加入到可用的Follower列表中。

四、总结

至此,我们已经说明了ZooKeeper如何在一致性和可用性之间做出权衡,并提供分布式数据一致性服务。ZooKeeper的数据一致性是最终一致性和单调一致性,并不能保证实时一致性。ZooKeeper的“过半写”策略,保证了只要ZooKeeper有一半机器正常就可以对外提供服务,保证了可用性,这里相对牺牲了需要服务器全票通过的一致性保证。ZAB协议重点需要关注它的两种工作模式如何运行,以及崩溃恢复模式如何处理消息广播模式中可能出现的数据一致性问题。


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页