ZAB协议概述

ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)的协议作为其数据一致性的核心算法。

ZAB协议是为分布式协调服务ZooKeeper专门设计的一种支持漰溃恢复的原子广播协议。

ZooKeeper实现了一种主备模式的系统架构来保持集群中各副本之间数据的一致性。具体,ZooKeeper使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用ZAB的原子广播协议,将服务器的状态变更以事务Proposal的形式广播到所有的副本进程上去。ZAB协议的这个主备模型架构保证了同一时刻集群中只能够有一个主进程来广播服务器的状态变更,因此能够很好地处理客户端大量并发请求。

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

ZAB协议介绍

ZAB协议的两种基本模式:崩溃恢复模式和消息广播模式。

崩溃恢复模式

  • ZAB协议会让ZK集群进入崩溃恢复模式的情况如下:

(1)当服务框架在启动过程中
      (2)当Leader服务器出现网络中断,崩溃退出与重启等异常情况。
      (3)当集群中已经不存在过半的服务器与Leader服务器保持正常通信。

  • ZAB协议进入恢复崩溃模式会做什么事情?

(1)当Leader出现问题,则进入恢复模式并选举出新的Leader服务器。当选举出新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成状态同步(数据同步),退出崩溃恢复模式。进入消息广播模式。
      (2)当新加入一台机器到集群中,如果此时集群已经存在一个Leader服务器在负责进行消息广播,那么新加入的服务器就会自觉地进入数据恢复模式。找到Leader服务器,并与其进行数据同步,然后进入消息广播模式,一起参与到消息广播流程中去。

ZAB的消息广播

ZAB协议与二阶段提交协议不同的是,ZAB协议在二阶段提交过程中,移除了中断逻辑。
ZAB协议在有过半的Follower服务器已经反馈Ack之后就开始提交Proposal了,而不需要等待集群中所有Follower服务器都反馈响应。
关于ZAB在Leader出现单点宕机如何保证事务提交,保证数据一致性,则引入崩溃恢复模式来解决这个问题。
ZAB的消息广播协议是基于具有FIFO(先进先出)特性的TCP协议来进行网络通信,保证消息广播过程中消息的接收与发送的顺序性。
在整个消息广播过程中,Leader服务器会为每一个事务请求的处理步骤:
        (1)Leader服务器会为事务请求生成一个全局的的递增事务ID(即ZXID),保证每个消息的因果关系的顺序。
        (2)Leader服务器会为该事务生成对应的Proposal,进行广播。
        (3)Leader服务器会为每一个Follower服务器都各自分配一个单独的队列,然后将需要广播的事务Proposal依次放入这些队列中去,并根据FIFO策略进行消息发送。
        (4)每一个Follower服务器在接收到这个事务Proposal之后,首先以日志形式写入本地磁盘,并且成功写入后反馈给Leader服务器一个Ack响应
        (5)当Leader服务器接收超过半数的Follower的Ack响应,Leader自身也会完成对事务的提交。同时就会广播一个Commit消息给所有的Follower服务器以通知进行事务提交。每一个Follower服务器在接收到Commit消息后,也会完成对事务的提交。

ZAB的崩溃恢复

基本特性,确保当Leader出现单点问题,在新选举出Leader后,保证数据一致性

  • ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交

(1)假设一个事务在Leader服务器上被提交了,并且已经得到了过半Follower服务器的Ack反馈,但是在它将Commit消息发送给所有Follower机器之前,Leader服务器挂了。
        (2)server1是Leader,C2是在Leader上完成事务提交,当通知Follower服务器Commit时挂掉,保证C2在Server2和Server3上提交

  • ZAB协议需要确保丢弃那些只在Leader服务器上被提出的事务。

(1)假设初始的Leader服务器Server1在提出一个事务Proposal3(P3)之后,还没有给Follower发送请求,希望得到ack之前,挂了。则要丢弃P3事务。

ZAB的Leader选举算法要求

数据同步
        (1)旧Leader宕机后,选举新Leader中,旧的Leader重启后不可能再次成为这次选举的新Leader。
        (2)旧Leader宕机后,在剩下的Follower服务器选取新Leader的标准,一定是事务ID最大的那个Follower成为新Leader。(即数据同步最新的那台Follower服务器)
        (3)事务ID(ZXID)是64位的数字。其中低32位可以靠做是一个简单的单调递增的计数器,高32位则代表一个Leader从生到死的epoch编号。
        (4)新Leader选举出来,从事务proposal中分析出旧Leader的epoch编号,并递增1,作为新的事务ID的高32位,然后新事务ID的低32位从0位重新开始计数。
        (5)新Leader通过事务ID和所有的Follower机器上的事务ID进行对比,确保数据同步。保证数据在所有的Follower上与之达成同步。旧Leader上新被提出的事务被抛弃。当数据达到同步,才将Follower服务器加入可用的Follower服务器列表。然后开始消息广播。

ZAB的深入

【1】系统模式
ZAB协议需要构建的分布式系统模型,通常在一个由一组进程N={P1,P2,P3....Pn}组成的分布式系统中,其中每一个进程都具有各自的存储设备,各个进程之间通过相互通信来实现消息的传递。
一个进程正常状态称为UP状态。如果一个进程崩溃了,我们成为DOWN状态。
事实上当集群中存在过半的处于UP状态的进程组成了一个进程子集之后,就可以进行正常的消息广播。我们将这样的一个进程子集称为Quorum(下文中使用Q来表示)
一个ZK集群必须满足:Q属于N的子集。Q1和Q2两个子集的交集不是空。
我们使用Pi和Pj来分别表示进程集合N中的两个不同进程,使用Cij来表示进程Pi和Pj之间的网络通信通道,其满足如下两个基本特性

【2】问题描述
ZooKeeper是一个高可用的分布式协调服务,在雅虎的很多大型系统上得到应用。这类应用有个共同的特点,即通常都存在大量的客户端进程,并且都依赖ZooKeeper来完成一系列诸如可靠的配置存储和运行时状态记录等分布式协调工作。
因此ZooKeeper必须具备高吞吐和低延迟的特性,并且能够很好地在高并发情况下完成分布式数据的一致性处理。同时能够优雅地处理运行时故障,并且具备快速地从故障中恢复过来的能力。