DDBS ZAB
我们之前讲述了 Paxos 一致性算法,现在我们来看ZAB 协议,该协议应该是所有一致性协议中生产环境中应用最多的了。为什么呢?因为他是为 Zookeeper 设计的分布式一致性协议!
ZAB 协议介绍
ZAB 协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议)。
Zookeeper 是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面,Zookeeper 并没有使用 Paxos ,而是采用了 ZAB 协议。
ZAB 协议定义:ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复和原子广播协议。下面我们会重点讲这两个东西。
基于该协议,Zookeeper 实现了主从模式的系统架构来保持集群中各个副本之间数据一致性。关于主从系统,我以前在zk中写的很清楚,不再赘述。
zookeeper主从系统
在数据一致性中,主从系统如下:
现在,重点介绍消息广播和崩溃恢复。整个 Zookeeper 就是在这两个模式之间切换。 简而言之,当 Leader 服务可以正常使用,就进入消息广播模式,当 Leader 不可用时,则进入崩溃恢复模式。
消息广播
ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个2PC。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成一个事务 Proposal,将其发送给所有 Follwer ,然后,根据所有 Follwer 的反馈,如果超过半数成功响应,则执行 commit 操作(先提交自己,再发送 commit 给所有 Follwer)。
基本上,整个广播流程分为 3 步骤:
- 将数据都复制到 Follwer 中
-
等待 Follwer 回应 Ack,最低超过半数即成功
-
当超过半数成功回应,则执行 commit ,同时提交自己
通过以上 3 个步骤,就能够保持集群之间数据的一致性。
一些细节:
- 在 Leader 和 Follwer 之间还有一个消息队列,用来解耦他们之间的耦合,解除同步阻塞。
- Leader 在收到客户端请求之后,会将这个请求封装成一个事务,并给这个事务分配一个全局递增的唯一 ID,称为事务ID(ZXID),ZAB 需要保证事务的顺序,因此必须将每一个事务按照 ZXID 进行先后排序然后处理。
- zookeeper集群中为保证任何所有进程能够有序的顺序执行,只能是 Leader 服务器接受写请求,即使是 Follower 服务器接受到客户端的请求,也会转发到 Leader 服务器进行处理。
- 实际上,这是一种简化版本的 2PC,不能解决单点问题。等会我们会讲述 ZAB 如何解决单点问题(即 Leader 崩溃问题)。
崩溃恢复
Leader 崩溃怎么办?还能保证数据一致吗?如果 Leader 先本地提交了,然后 commit 请求没有发送出去,怎么办?
实际上,当 Leader 崩溃,即进入我们开头所说的崩溃恢复模式(崩溃即:Leader 失去与过半 Follwer 的联系)。下面来详细讲述。
- 假设1:Leader 在复制数据给所有 Follwer 之后崩溃,怎么办?
- 假设2:Leader 在收到 Ack 并提交了自己,同时发送了部分 commit 出去之后崩溃怎么办?
针对这些问题,ZAB 定义了 2 个原则:
能够确保提交已经被 Leader 提交的事务,同时丢弃已经被跳过的事务。
恢复模式大致可以分为四个阶段:
- 当leader崩溃后,集群进入选举阶段,开始选举出潜在的新leader(一般为集群中拥有最大ZXID的节点)
- 进入发现阶段,follower与潜在的新leader进行沟通,如果发现超过法定人数的follower同意,则潜在的新leader将epoch加1,进入新的纪元。新的leader产生
3.集群间进行数据同步,保证集群中各个节点的事务一致 - 集群恢复到广播模式,开始接受客户端的写请求
当 leader在commit之后但在发出commit消息之前宕机,即只有老leader自己commit了,而其它follower都没有收到commit消息 新的leader也必须保证这个proposal被提交.(新的leader会重新发送该proprosal的commit消息)
当 leader产生某个proprosal之后但在发出消息之前宕机,即只有老leader自己有这个proproal,当老的leader重启后(此时左右follower),新的leader必须保证老的leader必须丢弃这个proprosal.(新的leader会通知上线后的老leader截断其epoch对应的最后一个commit的位置)