【Zookeeper】--ZAB (Zookeeper Atomic Broadcast)协议

#前言
     Zookeeper 是一个典型的分布式数据一致性的解决方案。在解决分布式系统数据一致性方面,Zookeeper并没有采用Paxos 算法,而是使用了一种被称为ZAB(Zookeeper Atomic Broadcast,原子消息广播协议)的一致性协议。
#正文
##

ZAB && Paxos

    ZAB 协议并不像Paxos 算法那样,是一种通用的分布式一致性算法,它是专门为分布式协调服务Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议,基于该协议,Zookeeper 实现了一种主备模式的系统架构来保持集群中各副本之间数据的一致性。
##

ZAB 协议的核心

    所有事务请求必须有一个全局唯一的服务器来协调处理,这样的服务器被成为Leader服务器,而余下的其他服务器则称为Follower服务器。Leader服务器负责将一个客户端事务请求转换成一个事务Proposal(提议),并将该Proposal 分发给集群中所有的Follower服务器。之后Leader 服务器需要等待所有的Follower服务器的反馈,一旦超过半数的Follower 服务器进行了正确的反馈后,那么Leader就会再向所有的Follower 服务器分发Commit消息,要求其将前一个Proposal进行提交。
##
ZAB 协议介绍

    ZAB 协议包括两种基本的模式:崩溃恢复和消息广播。
    当整个服务框架在启动过程中,或者是当Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并选举产生新的Leader服务器。当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式。
    状态同步是指数据同步,用来保证集群中存在过半的机器能够和Leader服务器的数据状态保持一致。

    当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步,那个整个服务器框架就可以进入消息广播模式了。Zookeeper设计成只允许唯一的一个Leader 服务器来进行事务请求的处理。Leader服务器在接收到客户端的事务请求后,会生成对应的事务提案并发起一轮广播协议;而如果集群中其他机器收到客户端的事务请求,那么这些非Leader 服务器会首先将这个事务请求转发给Leader服务器。
###

ZAB协议 的二阶段提交协议

     在ZAB协议的二阶段提交过程中,移除了中断逻辑(2PC中,所有的Follower服务器要么正常反馈Leader 提出的事务Proposal,只要任何一个Follower 服务器反馈失败,就会中断Leader服务器的事务请求),改成 可以在过半的Follower服务器已经反馈ACK就可以开始提交事务Proposal了,而不需要等待集群中所有的Follower 服务器都反馈响应;
     但是这种情况下,无法处理Leader 服务器崩溃退出而带来的数据不一致的问题,因此ZAB协议中添加了另外一个模式,即崩溃恢复模式;
     整个消息广播协议是基于具有FIFO 特性的TCP协议来进行网络通信的,因此能够很容易地保证消息广播过程中消息接受与发送的顺序性。

###

消息广播

     ZAB协议的消息广播过程使用的是一个原子广播协议,针对客户端的事务请求,Leader服务器会为其生成对应的事务Proposal,并将其发送给集群中剩余所有的机器,然后再分别收集各自的选票,最后进行事务提交。如下图是ZAB协议消息广播流程的示意图:
【Zookeeper】--ZAB (Zookeeper Atomic Broadcast)协议
     在广播事务Proposal 之前,Leader 服务器会为每个事务请求生成对应的Proposal 来进行广播,并且为整个事务Proposal 分配一个全局单调递增的唯一ID,称为事务ID(ZXID),保证事务Proposal处理的先后顺序性。
     在消息广播过程中,Leader 服务器为每一个Follower 服务器各自分配一个单独的队列,然后将需要广播的事务Proposal 依此放入到这些队列中,并且根据FIFO策略进行消息发送。每个Follower 服务器在接收到这个事务Proposal之后,都会首先将其以事务日志的形式写入到本地磁盘中去,并且在写入成功后反馈给Leader服务器一个Ack响应。当Leader 服务器 接收到超过半数Follower 的ACK 响应后,就会广播一个Commit 消息给所有的Follower 服务器以通知其进行事务提交,同时Leader 自身也会完成对事务的提交,而每一个Follower 服务器在接收到CommIt 消息后,也会完成对事务的提交。
【Zookeeper】--ZAB (Zookeeper Atomic Broadcast)协议

###

崩溃恢复

    一旦Leader 服务器出现奔溃,或者说由于网络原因导致Leader服务器失去了与过半的Follower 联系,那么就会进入崩溃恢复模式,为了保证程序的正确运行,整个恢复过程结束后需要选举出一个新的Leader 服务器。
    ZAB 协议规定了如果一个事务Proposal 在一台机器上被处理成功,那么应该在所有的机器上都被处理成功,哪怕机器出现故障。
    ZAB协议需要保证的特性
    1、已经在Leader服务器上提交的事务最终被所有服务器都提交
    假设一个事务在 Leader 服务器上被提交了,并且已经得到过半 Follower 服务器的Ack 反馈,但是在它将 Commit 消息发送给所有 Follower 机器之前, Leader 服务器挂了,针对这种情况, ZAB 协议就需要确保该事务最终能够在所有的服务器上都被提交成功,否则将出现不一致。
    2、丢弃那些只在Leader 服务器上被提出的事务
    假设初始的 Leader 服务器 在提出了一个事务之后就崩溃退出了,导致集群中的其他服务器都没有收到这个事务,当该服务器恢复过来再次加入到集群中的时候 ,ZAB协议需要确保丢弃这个事务。
    为了保证这些特性,Leader选举算法在设计时就需要保证新选举出来的Leader 服务器拥有集群中所有机器最高编号(ZXID 最大)的事务Proposal
###
数据同步中ZAB协议是如何处理那些需要被丢弃的失去Proposal 的?

     在ZAB协议的事务编号ZXID设计中,ZXID 是一个64位的数字,其中低32位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader 服务器在产生一个新的事务Proposal的时候,都会对该计数器进行加1操作;而高32位则代表了Leader周期epoch的编号,每当选举出一个新的Leader服务器,就会从Leader 服务器上取出其本地日志中最大事务Proposal的ZXID,并从该ZXID中解析出对应的epoch值,然后再对其进行加1 的操作,之后就会以此编号作为新的epoch,并将低32位 置0来开始生成新的ZXID。ZAB协议中的这一通过epoch编号来区分Leader周期变化的策略,能够有效地避免不同的Leader服务器错误地使用相同的ZXID 编号来提出不一样的事务Proposal的异常情况,这对于识别在Leader 崩溃恢复前后生成的Proposal非常有帮助,大大简化和提升了数据恢复流程。
     基于这样的策略,当一个包含了上一个Leader周期中尚未提交过的事务Proposal的服务器加入到集群中,发现此时集群中已经存在Leader ,将自身以Follower角色连接上Leader服务器之后,Leader 服务器会根据自己服务器上最后被提交的Proposal 来和Follower 服务器上的Proposal 进行比对,发现Follower 中有上一个Leader周期的事务Proposal时,Leader 会要求Follower 进行一个回退操作–回退到一个确实已经被集群中过半机器提交的最新的事务Proposal。

#总结
     Zookeeper的ZAB协议先了解到这里,感谢您的耐心阅读!