赞
踩
这篇博文算是对 Zookeeper Zab 协议的一次整体概述,主要是根据论文描述对 Zab 协议三大主要阶段详细过程的分析,先从整体上了解 Zab 的实现思路,在接下来的博文里我会进一步对三大阶段中的一些细节进行分析,同时会进一步分析 Zab 协议中空白的 Leader Election 算法(比如 Zookeeper 选择的 Fast Leader Election),最后会通过阅读 Zookeeper 源码来分析 Zookeeper 对于 Zab 协议的代码实现(Zookeeper 中的 Zab 协议代码实现是对 Zab 协议进行了一些优化后的版本)并分析 Zab 协议和 Raft 协议的一些区别和相似点。
Zab ( ZooKeeper Atomic Broadcast ) 协议或者说 Zab 算法是专门为 Zookeeper 设计的一种支持崩溃恢复 ( crash-recovery ) 的原子广播协议,因为 Zookeeper 是一种主备结构( primary-backup scheme ),所以 Zab 协议具备将主机的状态更新按顺序的广播到备份机的功能,并且能够保证在主机崩溃后不会出现主备数据不一致情况。
首先 Zab 算法主要包括三个阶段,即发现(Discovery)、同步(Synchronization)和广播(Broadcast),而每个 Zab 节点在任意某个时刻只会处于三个阶段中的某一个阶段,同时我们又称这三个阶段组成了一次 Zab 的迭代,在任何时候 Zab 节点都可能放弃当前的迭代,通过重新进入 Phase 1 开始新的迭代。
其次根据协议描述,Zab 节点存在两种可能的身份即 Leader 和 Follower,且 Leader 同时承担着主备结构(primary-backup scheme)中主机的责任,它会根据外部调用的顺序广播发布事务,而 Follower 则会根据 Zab 协议所规定的步骤来接收处理 Leader 发布的事务。
每一个 Zab 节点都存在一个 Leader Oracle(这个词我也不知道怎么翻译比较贴切,我觉得可以简单理解为是选票箱),这个 Leader Oracle 会提供给预期的 Leader 一个唯一的身份标识,在 Phase 1 的时候 Zab 节点会通过查看 Leader Oracle 来确定谁是它的 Leader,如果它发现自己是 Leader 那么它马上就会开始执行 Zab 协议中 Leader 的步骤。
但是需要注意的是在经过 Phase 1 后只能说该 Zab 节点根据 Leader Oracle 被选择成为了 Leader,但是此时它还没有完全建立起领导关系(LeaderShip),也就是它目前还不具备领导其它的 Zab 节点的能力,只有当它完成了 Phase 2 的同步后才真正建立了对其它 Zab 节点的领导关系,对于这一点的理解和分析会放在下一篇博文中,同时严格来说在 Phase 1 之前还存在一个 Leader 选举的过程,但是对于选举算法的选择 Zab 协议是没有进行规定的,实现者可以根据自己的需要来选择不同的选举算法。
在 Zab 算法中有几个比较重要的持久化变量,它们直接贯穿 Zab 算法的三大阶段,因此在开始正式解析 Zab 算法之前我们先大致了解一下这三个变量的作用(这里先直接使用论文中的定义方式,在后面分析流程时会使用别名来便于大家理解)。
首先 Follower f 给未来预期的 Leader l 通过发送 CEPOCH(f.p) 来传递其确认过的最后一个更新 Epoch 提议 NEWEPOCH(e’) 的纪元信息 f.p;
Leader l 一旦接收到达到法定数量的 Follower 发送的 CEPOCH(e) ,则立即发送 NEWEPOCH(e’) 给刚刚发送过 CEPOCH(e) 的 Follower,其中这里的 e’ 记为比刚刚接收到的所有 CEPOCH(e) 中的 e 都大的纪元(e’ = emax+1),并且此处开始将达到法定数量时发送过 CEPOCH(e) 的 Followers 记为集合 Q ;
Follower 接收到 Leader l 发送的 NEWEPOCH(e’) 提议即开始进行判断,如果 f.p < e’ 则意味着新纪元 e’ 大于其最后接收到的更新纪元提议中的纪元,因此更新 f.p 为 e’ 表示其接收到的最后一个更新纪元提议的纪元为 e’ ,同时发送 ACK-E(f.a ,hf) 给 Leader l 确认 NEWEPOCH(e’) 提议,其中 f.a 表示其最后确认过的更新 Leader 提议 NEWLEADER(e’,T) 的纪元信息,而 hf 代表其的历史数据记录,到这里 Follower 就完成了 Phase 1 ;
Leader l 一旦接收到达到法定数量的 Follower 对 NEWEPOCH(e’) 的确认,则立即从所有回复的 ACK-E(f.a ,hf) 中挑选合适的 hf 作为初始化数据 Ie’(这里也可以理解为从集合 Q 的 Follower 中挑选包含合适 hf 的 Follower ),具体的挑选规则为:对于 f1 和 f2 两个 Follower 回复的 ACK-E(f1.a ,hf1) 和 ACK-E(f2.a ,hf2) ,如果 f1.a < f2.a 则选择 hf2 ;若存在 f1.a == f2.a ,则当 f1.zxid <= f2.zxid 选择 hf2,总结一下也就是首先判断 ACK 中 f.a 的值,f.a 值大者获选,若两者的 f.a 相等则继续判断 f.zxid 的值,f.zxid 值大者获选,到这里 Leader l 就完成了 Phase 1;
首先未来预期的 Leader l 会给 Phase 1 中 Q 集合里所有的 Follower 发送更新 Leader 的提议 NEWLEADER(e’,Ie’) ;
Follower 接收到 Leader l 发送的 NEWLEADER(e’, Ie’) 提议后开始进行判断,如果 f.p ≠ e’ 则立即回到 Phase 1 的第一步开始新的轮回,如果 f.p == e’ 则开始执行下面的原子操作:首先更新 f.a 为 e’ ,然后接收 Ie’ 中所有纪元为 e’ 的数据,将自身的 hf 设置为 Ie’ ,完成上述原子操作最后回复确认 NEWLEADER(e’, Ie’) 提议的信息给 Leader l ;
Leader l 一旦接收到达到法定数量 Follower 对 NEWLEADER(e’, Ie’) 提议的确认就会给所有回复的 Follower(也即 Phase 1 的 Q 集合中所有的 Follower )发送 commit 提议,到这里 Leader l 完成 Phase 2 ;
当 Follower 接收到 Leader l 发送的 commit 提议后会按照 Ie’ 中的顺序对接收到的 Ie’ 中的事务依次进行提交,到这里 Follower 完成 Phase 2 ;
Leader l 按顺序递增 zxid 后给 Phase 2 中所有已确认关系的 Follower(也即 Phase 1 的 Q 集合中所有的 Follower )发送纪元为 e’ 的提议 (e’,<v,z>),这里因为在 Phase 2 中已经根据 Ie’ 完成了前面所有 e’ 纪元提议的 commit ,所以可以认为到目前为止对于纪元为 e’ 的提议的 zxid 都是顺序递增的;
首先如果 Follower 起初正处于 Leading 状态,则调用 ready(e’) ,否则 Follower 将按照 Leader l 发送的顺序接收提议,并将其添加到 hf 的尾部,最后回复 ACK 确认给 Leader l ;
当 Leader l 接收到达到法定数量 Follower 回复的对于提议 (e’,<v,z>) 的 ACK 确认信息后,就会向它们发送 COMMIT(e’,<v,z>) 提议指示 Follower 提交它们刚刚接收的提议 (e’,<v,z>) ;
当 Follower 接收到 Leader l 发送的 COMMIT(e’,<v,z>) 提议后就会通过调用 abdeliver(<v,z>) 方法来提交包括 (e’,<v,z>) 提议在内的和与其同一纪元且排在其前面的所有 (e’,<v’,z’>) 提议,其中存在 <v’,z’> ∈ hf 且 z’ < z;
同时在整个 Phase 3 中如果 Leader l 接收到来自 Follower 的 CEPOCH(e) 信息就会一次性的回复 NEWEPOCH(e’) 和 NEWLEADER(e’, Ie’ ◦ βe’) 两个提议来同步该 Follower ;
如果 Leader l 在发送完 NEWEPOCH(e’) 和 NEWLEADER(e’, Ie’ ◦ βe’) 两个提议后接收到该 Follower 对 NEWLEADER(e’, Ie’ ◦ βe’) 的 ACK 确认信息,就会直接发送 commit 提议让该节点提交可同步的事务,从而让该 Follower 完成 Phase 2 进入到 Phase 3,同时 Leader l 也会将该节点添加到自己的发送目标集合 Q 中;
Zab: High-performance broadcast for primary-backup systems
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。