分布式理论(七)—— 一致性协议之 ZAB

前言

在前面的文章中,咱们说了不少一致性协议,好比 Paxos,Raft,2PC,3PC等等,今天咱们再讲一种协议,ZAB 协议,该协议应该是全部一致性协议中生产环境中应用最多的了。为何呢?由于他是为 Zookeeper 设计的分布式一致性协议!算法

1. 什么是 ZAB 协议? ZAB 协议介绍

  1. ZAB 协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议)。服务器

  2. Zookeeper 是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面,Zookeeper 并无使用 Paxos ,而是采用了 ZAB 协议。架构

  3. ZAB 协议定义:ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持 崩溃恢复原子广播 协议。下面咱们会重点讲这两个东西。异步

  4. 基于该协议,Zookeeper 实现了一种 主备模式 的系统架构来保持集群中各个副本之间数据一致性。具体以下图所示:分布式

image.png

上图显示了 Zookeeper 如何处理集群中的数据。全部客户端写入数据都是写入到 主进程(称为 Leader)中,而后,由 Leader 复制到备份进程(称为 Follower)中。从而保证数据一致性。从设计上看,和 Raft 相似。设计

  1. 那么复制过程又是如何的呢?复制过程相似 2PC,ZAB 只须要 Follower 有一半以上返回 Ack 信息就能够执行提交,大大减少了同步阻塞。也提升了可用性。

简单介绍完,开始重点介绍 消息广播崩溃恢复整个 Zookeeper 就是在这两个模式之间切换。 简而言之,当 Leader 服务能够正常使用,就进入消息广播模式,当 Leader 不可用时,则进入崩溃恢复模式。日志

2. 消息广播

ZAB 协议的消息广播过程使用的是一个原子广播协议,相似一个 二阶段提交过程。对于客户端发送的写请求,所有由 Leader 接收,Leader 将请求封装成一个事务 Proposal,将其发送给全部 Follwer ,而后,根据全部 Follwer 的反馈,若是超过半数成功响应,则执行 commit 操做(先提交本身,再发送 commit 给全部 Follwer)。code

基本上,整个广播流程分为 3 步骤:blog

1.将数据都复制到 Follwer 中排序

image.png

  1. 等待 Follwer 回应 Ack,最低超过半数即成功

image.png

  1. 当超过半数成功回应,则执行 commit ,同时提交本身

image.png

经过以上 3 个步骤,就可以保持集群之间数据的一致性。实际上,在 Leader 和 Follwer 之间还有一个消息队列,用来解耦他们之间的耦合,避免同步,实现异步解耦。

还有一些细节:

  1. Leader 在收到客户端请求以后,会将这个请求封装成一个事务,并给这个事务分配一个全局递增的惟一 ID,称为事务ID(ZXID),ZAB 兮协议须要保证事务的顺序,所以必须将每个事务按照 ZXID 进行前后排序而后处理。

  2. 在 Leader 和 Follwer 之间还有一个消息队列,用来解耦他们之间的耦合,解除同步阻塞。

  3. zookeeper集群中为保证任何全部进程可以有序的顺序执行,只能是 Leader 服务器接受写请求,即便是 Follower 服务器接受到客户端的请求,也会转发到 Leader 服务器进行处理。

  4. 实际上,这是一种简化版本的 2PC,不能解决单点问题。等会咱们会讲述 ZAB 如何解决单点问题(即 Leader 崩溃问题)。

3. 崩溃恢复

刚刚咱们说消息广播过程当中,Leader 崩溃怎么办?还能保证数据一致吗?若是 Leader 先本地提交了,而后 commit 请求没有发送出去,怎么办?

实际上,当 Leader 崩溃,即进入咱们开头所说的崩溃恢复模式(崩溃即:Leader 失去与过半 Follwer 的联系)。下面来详细讲述。

假设1:Leader 在复制数据给全部 Follwer 以后崩溃,怎么办?
假设2:Leader 在收到 Ack 并提交了本身,同时发送了部分 commit 出去以后崩溃怎么办?

针对这些问题,ZAB 定义了 2 个原则:

  1. ZAB 协议确保那些已经在 Leader 提交的事务最终会被全部服务器提交。
  2. ZAB 协议确保丢弃那些只在 Leader 提出/复制,但没有提交的事务。

因此,ZAB 设计了下面这样一个选举算法:
可以确保提交已经被 Leader 提交的事务,同时丢弃已经被跳过的事务。

针对这个要求,若是让 Leader 选举算法可以保证新选举出来的 Leader 服务器拥有集群总全部机器编号(即 ZXID 最大)的事务,那么就可以保证这个新选举出来的 Leader 必定具备全部已经提交的提案。
并且这么作有一个好处是:能够省去 Leader 服务器检查事务的提交和丢弃工做的这一步操做。

image.png

这样,咱们刚刚假设的两个问题便可以解决。假设 1 最终会丢弃调用没有提交的数据,假设 2 最终会同步全部服务器的数据。这个时候,就引出了一个问题,如何同步?

4. 数据同步

当崩溃恢复以后,须要在正式工做以前(接收客户端请求),Leader 服务器首先确认事务是否都已经被过半的 Follwer 提交了,便是否完成了数据同步。目的是为了保持数据一致。

当全部的 Follwer 服务器都成功同步以后,Leader 会将这些服务器加入到可用服务器列表中。

实际上,Leader 服务器处理或丢弃事务都是依赖着 ZXID 的,那么这个 ZXID 如何生成呢?

答:在 ZAB 协议的事务编号 ZXID 设计中,ZXID 是一个 64 位的数字,其中低 32 位能够看做是一个简单的递增的计数器,针对客户端的每个事务请求,Leader 都会产生一个新的事务 Proposal 并对该计数器进行 + 1 操做。

而高 32 位则表明了 Leader 服务器上取出本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,而后再对这个值加一。

image.png

高 32 位表明了每代 Leader 的惟一性,低 32 表明了每代 Leader 中事务的惟一性。同时,也能让 Follwer 经过高 32 位识别不一样的 Leader。简化了数据恢复流程。

基于这样的策略:当 Follower 连接上 Leader 以后,Leader 服务器会根据本身服务器上最后被提交的 ZXID 和 Follower 上的 ZXID 进行比对,比对结果要么回滚,要么和 Leader 同步。

5. 总结

到了总结的时刻了。

ZAB 协议和咱们以前看的 Raft 协议其实是有类似之处的,好比都有一个 Leader,用来保证一致性(Paxos 并无使用 Leader 机制保证一致性)。再有采起过半即成功的机制保证服务可用(实际上 Paxos 和 Raft 都是这么作的)。

ZAB 让整个 Zookeeper 集群在两个模式之间转换,消息广播和崩溃恢复,消息广播能够说是一个简化版本的 2PC,经过崩溃恢复解决了 2PC 的单点问题,经过队列解决了 2PC 的同步阻塞问题。

而支持崩溃恢复后数据准确性的就是数据同步了,数据同步基于事务的 ZXID 的惟一性来保证。经过 + 1 操做能够辨别事务的前后顺序。

好了,关于 ZAB 协议就介绍到这里,篇幅有限,不免疏漏。

good luck!!!!

引用

《从 Paxos 到 Zookeeper——分布式一致性原理和实践》