什么是Zab协议
定义:
ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeper Atomic Broadcast(ZAB,ZooKeeper原子消息广播协议)的协议作为其数据一致性的核心算法。ZAB协议并不像Paxos算法那样,是一种通用的分布式一致性算法,它是一种特别为ZooKeeper设计的崩溃可恢复的原子消息广播算法。
作用:
在ZooKeeper中,主要依赖ZAB协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了一种主备模式的系统架构来保持集群中各副本之间数据的一致性。
基本概念:
所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 Leader服务器,而余下的其他服务器则成为 Follower 服务器。Leader 服务器负责将一个客户端事务请求转换成一个事务 Proposal(提议),并将该 Proposal 分发给集群中所有的Follower 服务器。之后 Leader 服务器需要等待所有 Follower 服务器的反馈,一旦超过半数的 Follower 服务器进行了正确的反馈后,那么 Leader 就会再次向所有的 Follower服务器分发Commit消息,要求其将前一个Proposal进行提交。
分析Zab协议
zab协议由五阶段组成
- 选Leader阶段
- 发现阶段
- 同步阶段
- 消息广播阶段
- 崩溃恢复阶段
1.选Leader阶段
选Leader阶段这里不重复描述了,可以看之前的博客:https://blog.csdn.net/y510662669/article/details/106624186
2.发现阶段
Followers 跟准 Leader 进行通信,同步 Followers 最近接收的事务提议。这个一阶段的主要目的是发现当前大多数节点接收的最新提议,并且准 Leader 生成新的 epoch,让 Followers 接受,更新它们的 acceptedEpoch。
Epoch是什么?Epoch是Leader选举轮次的编号。
Epoch的详细解释:
ZXID是一个64位的数字,其中低 32 位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader服务器在产生一个新的事务Proposal的时候,都会对该计数器进行加1操作;而高32位则代表了Leader周期epoch的编号,每当选举产生一个新的Leader服务器,就会从这个Leader服务器上取出其本地日志中最大事务Proposal的ZXID,并从该ZXID中解析出对应的epoch值,然后再对其进行加1操作,之后就会以此编号作为新的epoch。
Epoch的作用:
Epoch编号来区分 Leader 周期变化的策略,能够有效地避免不同的 Leader 服务器错误地使用相同的ZXID编号提出不一样的事务Proposal的异常情况。
发现阶段的流程:
3.同步阶段
同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。只有当 quorum 都同步完成,准 leader 才会成为真正的 leader。follower 只会接收 zxid 比自己的 lastZxid 大的提议。
4.消息广播阶段
ZAB协议的消息广播过程使用的是一个原子广播协议,类似于一个二阶段提交过程(可以理解为2pc,但是比2pc要简单)。针对客户端的事务请求,Leader服务器会为其生成对应的事务Proposal,并将其发送给集群中其余所有的机器,然后再分别收集各自的选票,最后进行事务提交。
1) Leader发出一个Propose提议。
2)每一个Follower收到后,都会首先将其以事务日志的形式写入到本地磁盘中去。写入成功后会返回给Leader一个Ack。
3)当Leader收到超过半数的Ack后,就会广播一个Commit消息给所有的Follower服务器以通知其进行事务提交,Leader自身也会完成对事务的提交。
4)Follower收到commit消息后,会完成对事务的提交。
5.崩溃恢复阶段
第一个保证点
ZAB协议需要确保那些已经在Leader服务器上提交的事务最终被所有服务器都提交。
典型的例子:在集群正常运行过程中的某一个时刻,Server1 是 Leader 服务器,其先后广播了消息 P1、P2、C1、P3 和 C2,其中,当Leader服务器将消息C2(C2是Commit Of Proposal2的缩写,即提交事务Proposal2)发出后就立即崩溃退出了。针对这种情况,ZAB协议就需要确保事务Proposal2最终能够在所有的服务器上都被提交成功,否则将出现不一致。
假设初始的 Leader 服务器 Server1 在提出了一个事务Proposal3 之后就崩溃退出了,从而导致集群中的其他服务器都没有收到这个事务Proposal。于是,当 Server1 恢复过来再次加入到集群中的时候,ZAB 协议需要确保丢弃Proposal3这个事务。因为选举是通过zxId对比来的,只要保证zxId最大就行了。这里就是通过zxId内部的epoch来保证的。
leader在发出commit之前挂了怎么办?
leader会重新选举,肯定会重新选举出一个zxId最大的再次作为leader。
leader在发出commit之后挂了怎么办?
发出去后,所有的follower都要执行提交。怎么保证所有的follower执行成功呢?只能说是大部分follower执行成功。
总结
- zab协议概括而言包括:领导者选举,过半机制,以及广播协议(简单版本2pc协议),通过这三大部分来保证数据一致性,整体zab的协议非常复杂,最好是能通过代码debug,这里是简单剖析了下,还有许多待完善的地方。
- epoch设计以及2pc协议都非常关键,需要进一步深入理解。
- 好文参考:https://juejin.im/post/5b924b0de51d450e9a2de615