ZAB协议的那些事?

1、什么是zab协议?

ZAB 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。服务器

Zab 协议分为两大块:架构

  • 广播(boardcast):Zab 协议中,全部的写请求都由 leader 来处理。正常工做状态下,leader 接收请求并经过广播协议来处理。
  • 恢复(recovery):当服务初次启动,或者 leader 节点挂了,系统就会进入恢复模式,直到选出了有合法数量 follower 的新 leader,而后新 leader 负责将整个系统同步到最新状态。

    1.1广播(boardcast)

    广播的过程其实是一个简化的二阶段提交过程:分布式

    1. Leader 接收到消息请求后,将消息赋予一个全局惟一的 64 位自增 id,叫作:zxid,经过 zxid 的大小比较便可实现因果有序这一特性。
    2. Leader 经过先进先出队列(经过 TCP 协议来实现,以此实现了全局有序这一特性)将带有 zxid 的消息做为一个提案(proposal)分发给全部 follower。
    3. 当 follower 接收到 proposal,先将 proposal 写到硬盘,写硬盘成功后再向 leader 回一个 ACK。
    4. 当 leader 接收到合法数量的 ACKs 后,leader 就向全部 follower 发送 COMMIT 命令,同事会在本地执行该消息。
    5. 当 follower 收到消息的 COMMIT 命令时,就会执行该消息
      广播过程

      相比于完整的二阶段提交,Zab 协议最大的区别就是不能终止事务,follower 要么回 ACK 给 leader,要么抛弃 leader,在某一时刻,leader 的状态与 follower 的状态极可能不一致,所以它不能处理 leader 挂掉的状况,因此 Zab 协议引入了恢复模式来处理这一问题。从另外一角度看,正由于 Zab 的广播过程不须要终止事务,也就是说不须要全部 follower 都返回 ACK 才能进行 COMMIT,而是只须要合法数量(2f+1 台服务器中的 f+1 台) 的follower,也提高了总体的性能。性能

    1.2恢复(recovery)

因为以前讲的 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

图 1-1

为了实现已经被处理的消息不能丢这个目的,Zab 的恢复模式使用了如下的策略:blog

  1. 选举拥有 proposal 最大值(即 zxid 最大) 的节点做为新的 leader:因为全部提案被 COMMIT 以前必须有合法数量的 follower ACK,即必须有合法数量的服务器的事务日志上有该提案的 proposal,所以,只要有合法数量的节点正常工做,就必然有一个节点保存了全部被 COMMIT 消息的 proposal 状态。
  2. 新的 leader 将本身事务日志中 proposal 但未 COMMIT 的消息处理。
  3. 新的 leader 与 follower 创建先进先出的队列, 先将自身有而 follower 没有的 proposal 发送给 follower,再将这些 proposal 的 COMMIT 命令发送给 follower,以保证全部的 follower 都保存了全部的 proposal、全部的 follower 都处理了全部的消息。
    经过以上策略,能保证已经被处理的消息不会丢

被丢弃的消息不能再次出现

这一状况会出如今如下场景:当 leader 接收到消息请求生成 proposal 后就挂了,其余 follower 并无收到此 proposal,所以通过恢复模式从新选了 leader 后,这条消息是被跳过的。 此时,以前挂了的 leader 从新启动并注册成了 follower,他保留了被跳过消息的 proposal 状态,与整个系统的状态是不一致的,须要将其删除。队列

如图 1-2 ,在 Server1 挂了后系统进入新的正常工做状态后,消息 3被跳过,此时 Server1 中的 P3 须要被清除。事务

图 1-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 清除。

2、总结

  • 主从架构下,leader 崩溃,数据一致性怎么保证?leader 崩溃以后,集群会选出新的 leader,而后就会进入恢复阶段,新的 leader 具备全部已经提交的提议,所以它会保证让 followers 同步已提交的提议,丢弃未提交的提议(以 leader 的记录为准),这就保证了整个集群的数据一致性。
  • 选举 leader 的时候,整个集群没法处理写请求的,如何快速进行 leader 选举?这是经过 Fast Leader Election 实现的,leader 的选举只须要超过半数的节点投票便可,这样不须要等待全部节点的选票,可以尽早选出 leader。

相关文章
相关标签/搜索