ZAB 协议是为分布式协调服务ZooKeeper专门设计的一种支持崩溃恢复的原子广播协议。
基于该协议,ZooKeeper 实现了一种主从模式的系统架构来保持集群中各个副本之间的数据一致性,就是使用单一的主进程接收客户端的事务请求(Leader服务器),并采用ZAB协议的原子广播协议,将主进程的状态变更以事务Proposal的形式广播到所有的副本进程上(Follower服务器)。
所有的事务请求必须有Leader服务器处理,Leader服务器将客户端请求转换成一个事务Proposal(提议),并将
该提议发送给集群中所有的Follower服务器,一旦超过半数的Follower服务器进行了正确的反馈后,Leader服务器会再次向所有的Follower服务器发送commit消息,要求其将前一个Proposal进行提交。
3.1 崩溃恢复模式
什么情况下会进行崩溃恢复模式:
1.集群启动过程中。
2.Leader服务器出现异常情况时。
什么情况下退出崩溃恢复模式:
新的Leader服务器已经产生,同时集群中有过半的Follower服务器与该Leader服务器完成了状态同步(数据状态保持一致)之后。
3.1.1 Leader选举算法
作用:
能够快速的选举出新的Leader,要让Leader自己知道自己已经被选举为Leader,还要让集群中其他机器快速的感知到这个新的Leader服务器。
需要考虑的两个在崩溃恢复过程中可能会出现的两个数据不一致的问题:
1.假设一个事务在Leader服务器上被提交了,并且已经得到过半Follower服务器的Ack反馈,但是在它将Commit消息发送给所有的Follower机器之前,Leader挂了,ZAB协议需要确保该事务最终能够在所有的服务器上提交成功,否则将出现不一致。
2.Leader服务器在提出一个事务之后就崩溃退出了,导致集群中的其他服务器没有收到这个事务,那么当这个Leader服务器恢复之后再次加入到集群中时(成为Follower服务器了),ZAB协议需要确保丢弃这个事务。
解决上述问题,ZAB协议的设计:
让Leader选举算法能够保证新选举出来的Leader服务器拥有集群中ZXID最大的事务Proposal,保证新的Leader一定具有所有已经提交的提案,重要的是可以省去Leader服务器检查事务的提交和丢弃工作这个步骤。
3.1.2 数据同步
此过程发生在Leader选举完成之后,正式开始工作(即接收客户端的事务请求,然后提出新的提案)之前。
同步过程:
1.如何处理那些需要被提交的事务:
Leader会为每一个Follower都准备一个队列,并将那些没有被Follower同步的事务以Proposal消息的形式逐个发送给Follower,并在每一个Proposal消息后紧接着在发送一个commit消息,等Follower将所有尚未同步的事务都从Leader上同步过来并成功入到本地数据库中后,Leader就会将该Follower加入到真正的可用Follower列表中,并开始之后的其他流程。
2.如何处理那些需要被丢弃的事务:
ZXID设计策略:
是64位的数据,低32位相当于单调递增计数器,Leader产生一个新的事务,计数器加1;高32位保存Leader周期epoch的编号,没产生一个新的Leader,就从这个Leader服务器上取出其本地日志中 最大事务的ZXID,对这个ZXID的epoch值加1,作为新的epoch,并将该ZXID低32位置0来开始新的ZXID。
处理丢弃事务过程:
基于ZXID设计策略,当一个包含了上一个Leader周期中尚未提交过的事务的服务器启动时,它无法成为Leader,当它加入到集群中时,只能以Follower角色连接上Leader服务器之后,Leader服务器根据自己服务器上最后被提交的事务和Follower服务器的事务进行比对,比对结果要求Follower进行一个回退操作,回退到已经被集群中过半机器提交的最新的事务。
3.2 消息广播模式
什么情况下会进行消息广播模式:
集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步后,整个集群就进入消息广播模式。此时如果新来一台Follower服务器,那么该服务器找到Leader所在服务器,并与其进行数据同步,然后一起参与到消息广播流程中。如果Follower服务器接收到客户端的事务(写数据请求),那么Follower服务器会将这个请求转发给Leader服务器。
具体过程描述:
1.Leader服务器为事务Proplsal分配ZXID(全局单调递增的唯一ID),然后进行广播。
2.广播过程中,leader服务器为每一个Follower服务器都各自分配一个单独的队列(FIFO策略),然后将需要广播的事务Proposal依次入队。
3.每一个Follower服务器收到这个事务后,以日志的形式写入磁盘,写入成功后,反馈给Leader服务器Ack响应。
4.Leader收到半数以上Follower的Ack响应后,再广播Commit消息给所有的Follower服务器进行事务提交,Leader自身也提交事务。
具体过程与二阶段提交有些类似,但是移除了中断逻辑,Follower服务器要么正常反馈Ack信息,要么抛弃Leader的事务。
ZAB设计中,每一个进程处于三种状态之一:
looking:Leader选举阶段
following:Follower服务器和Leader保持同步状态
leading:Leader服务器作为主进程领导状态
运行流程
1.集群中进程启动时,初始化状态都是looking状态,此时进程组中不存在Leader,所有处于此状态的进程,会试图选举一个新的Leader,
2.如果已经选举出Leader了,那么进程马上切换到following状态,并开始和Leader保持同步。
3.如果此时Leader挂掉,那么其余的Follower进程就会转换到looking状态,开始新一轮的Leader选举。
4.在完成了Leader选举和数据同步阶段之后准Leader进程才能真正成为Leader,并开始接收新的客户端事务请求。
5.在进行原子广播阶段,Leader进程与Follower进程通过心跳机制来感知彼此的情况,如果在超时时间内Leader进程无法收到过半的Follower进程的心跳检测,Leader会终止领导,并切换到looking状态,所有的Follower转换到looking状态,开始新一轮的Leader选举。
5.1 两者的联系
1.两者都存在一个类似于Leader进程的角色,负责协调多个Follower进程的运行。
2.Leader进程都会等待超过半数的Follower做出正确的反馈后,才会将一个提案进行提交。
3.ZAB协议中每个Proposal中都包含了一个epoch值,代表Leader周期,Paxos算法中,也存在这样的一个表示,名字为Ballot。
5.2 两者不同
1.Paxos算法中,一个新产生的主进程会进行两个阶段的工作,第一阶段读阶段,新的主进程会通过和所有其他的进程进行通信收集上一个主进程提出的提案,并将它们提交;第二阶段写阶段,当前主进程开始提出他自己的提案,
2.ZAB协议同样存在类似的读阶段(发现阶段),多了一个同步阶段,在同步阶段确保所有的Follower已经处理了之前Leader提交的事务(包括需要提交的和需要丢弃的)。一旦同步阶段完成后,ZAB会执行和Paxos算法类似的写阶段。
3.两者的设计目标不一致,ZAB用于构建一个高可用的分布式数据主备系统,Paxos算法用于构建一个分布式的数据一致性系统。
此文章参考《从PAXOS到ZOOKEEPER分布式一致性原理与实践》一书,将书中不容易理解记忆的地方使用自己的理解方式记录下来,如果错误之处,欢迎指正。