ZAB 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。服务器
Zab 协议分为两大块:架构
广播的过程其实是一个简化的二阶段提交过程:分布式
相比于完整的二阶段提交,Zab 协议最大的区别就是不能终止事务,follower 要么回 ACK 给 leader,要么抛弃 leader,在某一时刻,leader 的状态与 follower 的状态极可能不一致,所以它不能处理 leader 挂掉的状况,因此 Zab 协议引入了恢复模式来处理这一问题。从另外一角度看,正由于 Zab 的广播过程不须要终止事务,也就是说不须要全部 follower 都返回 ACK 才能进行 COMMIT,而是只须要合法数量(2f+1 台服务器中的 f+1 台) 的follower,也提高了总体的性能。性能
因为以前讲的 Zab 协议的广播部分不能处理 leader 挂掉的状况,Zab 协议引入了恢复模式来处理这一问题。为了使 leader 挂了后系统能正常工做,须要解决如下两个问题:设计
这一状况会出如今如下场景:当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向链接的客户端返回「成功」。可是若是在各个 follower 在收到 COMMIT 命令前 leader 就挂了,致使剩下的服务器并无执行都这条消息。日志
如图 1-1,消息 1 的 COMMIT 命令 Server1(leader)和 Server2(follower) 上执行了,可是 Server3 尚未收到消息 1 的 COMMIT 命令,此时 leader Server1 已经挂了,客户端极可能已经收到消息 1 已经成功执行的回复,通过恢复模式后须要保证全部机器都执行了消息 1。cdn
为了实现已经被处理的消息不能丢这个目的,Zab 的恢复模式使用了如下的策略:blog
这一状况会出如今如下场景:当 leader 接收到消息请求生成 proposal 后就挂了,其余 follower 并无收到此 proposal,所以通过恢复模式从新选了 leader 后,这条消息是被跳过的。 此时,以前挂了的 leader 从新启动并注册成了 follower,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,须要将其删除。队列
如图 1-2 ,在 Server1 挂了后系统进入新的正常工做状态后,消息 3被跳过,此时 Server1 中的 P3 须要被清除。事务
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 清除。