Fork me on GitHub

浅谈ZAB协议

众所周知,ZooKeeper 是一个开源的分布式协调服务,很多分布式的应用都是基于 ZooKeeper 来实现分布式锁、服务管理、通知订阅等功能。

那么 ZooKeeper 自身是如何在分布式环境下实现数据的一致性的呢?

答案就是ZooKeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)

谈ZAB之前我们先聊一聊 2PC。

2PC

两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。

运行过程

  1. 准备阶段:协调者询问参与者事务是否执行成功,参与者发回事务执行结果。
  2. 提交阶段:如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。

需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

问题

  1. 同步阻塞:所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。
  2. 单点问题:协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待,无法完成其它操作。
  3. 数据不一致:在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
  4. 太过保守:任意一个节点失败就会导致整个事务失败,没有完善的容错机制。

ZAB

现在再来看看ZAB是怎么解决上面的问题的。在我看来,ZAB就是 2PC变种 + 崩溃恢复,其中 崩溃恢复是解决协调者崩溃后发生的问题。

消息广播

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消息后,也会完成对事务的提交。

崩溃恢复

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

保证一致性的关键在于下面两点:

  1. ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交。
  2. ZAB协议需要确保丢弃那些只在Leader服务器上被提出的事务。

对于1来说,只需要通过选举找到当前集群中持有事务ID最大的那台机器,其他的服务器同步这台机器即可。

对于2来说, Zab 通过巧妙的设计 zxid 来实现这一目的。一个 zxid 是64位,高 32 是纪元(epoch)编号,每经过一次 leader 选举产生一个新的 leader,新 leader 会将 epoch 号 +1。低 32 位是消息计数器,每接收到一条消息这个值 +1,新 leader 选举后这个值重置为 0。这样设计的好处是旧的 leader 挂了后重启,它不会立即被重新选举为 leader,因为此时它的 zxid 肯定小于当前的新 leader。当旧的 leader 作为 follower 接入新的 leader 后,新的 leader 会让它将所有的拥有旧的 epoch 号的未被 COMMIT 的 proposal 清除。

扫描二维码,拯救贫困山区大学生!
-------------本文结束感谢您的阅读-------------