Zookeeper 从入门到入土⑨:ZAB 协议
1. 概述
Zookeeper 使用⼀个单⼀的主进程来接收并处理客户端的所有事务请求
并采用 ZAB ( Zookeeper Atomic Broadcast,原子广播协议),将服务器数据的状态变更以事务 Proposal 的形式广播到所有的副本进程中
读写请求官方压测:
3888 端口通信模型:
任何两个节点都互通
2. 恢复模式(选 Master + 数据同步)
官方压测 200ms 恢复
步骤:
- Leader 选举过程: Leader 与过半 Follower 失去联系,Follower 服务器都会将自己的服务器状态变更为 LOOKING,并进⼊ Leader 选举过程。
- 数据同步: ZAB 会选举产生新的 Leader 服务器,然后有过半(防止脑裂)的机器与该 Leader 服务器完成了数据同步之后会退出恢复模式。
注意的问题:
- ZAB 协议需要确保那些已经在 Leader 上提交的事务最终被所有服务器都提交
- ZAB 协议需要确保丢弃那些只在 Leader 上被提出但尚未发出的事务
ZAB 保证新选举出来的 Leader 服务器拥有集群中所有机器最高编号(即 ZXID 最大)事务 Id 的 Proposal 来解决上述问题
2.1. Leader 选举
Leader 所在的机器挂了或者失去大多数的 Follower 会进入恢复模式,进行新⼀轮的 Leader 选举。
服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是⼀致的。
选举算法:
通过 zoo.cfg 配置文件中的 electionAlg 属性指定(0-3)
FastLeaderElection 算法(值为 3。TCP 实现,zk 3.4.0 之后只保留了该算法,废弃了 0-2)
过程:
每个 Server 会将自身的(myid,ZXID)发送给集群以便通知其他 Server 自己的选择。
这是投给自己的票,因为此时还不知道其他 Server 的状态。例如 Server1 的 myid 为 1,ZXID 为 0,则发送(1, 0)
接受来自各个服务器的投票
集群的每个服务器收到投票后,判断该投票的有效性,如检查是否是本轮投票、是否来⾃ LOOKING 状态的服务器。
针对每⼀个投票,服务器都需要将别人的投票和自己的投票进行选择,以确定是否变更投票
- 比较 ZXID:如果接收到的投票的 ZXID 比自己的大,则当前 Server 认可收到的投票,并再次将该投票发送出去。反之,若接收到的投票的 ZXID 比自己的小,则不做任何操作
- 比较 myid:如果 ZXID 相同则比较 myid。myid 较⼤的投票会被认可并再次发送出去。反之,若接收到的 myid 比自己的小,则不做任何操作
统计投票
Server 都接收到其他 Server 的变更投票后会开始统计投票,如果一台 Server 中相同的投票超过半数则该投票对应的 myid 的 Server 成为 Leader。为什么过半机制中是大于,而不是大于等于。就是为了防止脑裂
改变服务器状态
⼀旦确定了 Leader,每个服务器就会更新⾃⼰的状态:如果是 Follower,那么就变更为 FOLLOWING,如果是 Leader,那么就变更为 LEADING。
2.2. 数据同步
数据同步消息方式:
消息类型 | 发送方向 | 说明 |
---|---|---|
DIFF | Leader -> Learner | 通知 Learner 即将与 Learner 进行增量方式的数据同步 |
TRUNC | Leader -> Learner | 触发 Learner 进行其内存数据库的回滚操作 |
SNAP | Leader -> Learner | 通知 Learner 即将与 Learner 进行全量方式的数据同步 |
UPTODATE | Leader -> Learner | 通知 Learner 已完成数据同步,可对外提供服务 |
服务器初始化消息类型:
消息类型 | 发送方向 | 说明 |
---|---|---|
OBSERVERINFO | Observer -> Leader | Observer 启动时发送自身的(myid,zxid)给 Leader,用于向 Leader 表明角色并注册自己 |
FOLLOWERINFO | Follower -> Leader | Follower 启动时发送自身的(myid,zxid)给 Leader,用于向 Leader 表明角色并注册自己 |
LEADERINFO | Leader -> Learner | Leader 接收到来自 Learner 的上述两类消息后会将当前 Leader 的 epoch 发送 Learner |
ACKEPOCH | Learner -> Leader | Learner 收到 LEADERINFO 消息后会将自己最新的 zxid 和 epoch 发送给 Leader |
NEWLEAEDER | Leader -> Learner | 足够多的 Follower 连上 Leader 或完成数据同步后,Leader 会向 Learner 发送当前 Leader 最新的 zxid |
过程:
Leader 加载快照: 重新加载本地磁盘上的数据快照至内存,并从日志文件中取出快照之后的所有事务操作,逐条应用至内存,并添加到已提交事务缓存 commitedProposals。
这样能保证日志文件中的事务操作,必定会应用到 leader 的内存数据库中。
确定同步方式:
获取 Learner 发送的
OBSERVERINFO/FOLLOWERINFO
信息(myid,zxid),即 id 和已提交过的最大消息 zxid。用 Learner 的最大 zxid 与 Leader 提交过的消息(commitedProposals)中的最小 zxid(min_zxid)和最大 zxid(max_zxid)分别作比对,确定采用哪种同步方式(DIFF 同步、TRUNC+DIFF 同步、SNAP 同步)。
- 如果该 zxid 介于 min_zxid 与 max_zxid 之间,但又不存在于 commitedProposals 中时,说明该 zxid 对应的事务需要 TRUNC 回滚
- 如果该 zxid 介于 min_zxid 与 max_zxid 之间且存在于 commitedProposals 中,则 Leader 需要将 zxid+1~max_zxid 间所有事务同步给 Learner(DIFF)
- 如果该 zxid == max_zxid,说明已经完全同步了数据同步: Leader 主动向所有 Learner 发送同步数据消息,每个 Learner 有自己的发送队列。
同步结束时,Leader 会向 Learner 发送 NEWLEADER 消息,同时 Learner 会反馈一个 ACK。当 Leader 接收到来自 Learner 的 ACK 消息后,就认为当前 Learner 已经完成了数据同步,然后进入 等待是否过半阶段。同步完成: 当 Leader 统计到收到了一半已上的 ACK 时,会向所有已经完成数据同步的 Learner 发送一个
UPTODATE
消息,用来通知 Learner 集群已经完成了数据同步,可以对外服务了。
3. 广播模式(事务操作节点同步)
原子广播协议特性:
- 原子性:要么成功,要么失败,不存在中间状态。(队列 + 2PC 实现)
- 广播:Leader 通知所有节点进行操作
有过半的 Follower 服务器完成了和 Leader 服务器的数据同步,那么就会进⼊消息⼴播模式。
扩容加入的新服务器会与 Leader 进行数据同步然后参与到消息⼴播流程中
Leader/Follower/Observer 都可直接处理读请求,从本地内存中读取数据并返回给客户端即可。
- 转发请求: Follower 接收到写请求后会转发给 Leader 来处理
- 发送事务消息: Leader 接收到写请求后会把该写请求转换成带有各种状态的事务,并会分配给 Proposal 一个单调递增的唯一 id(zxid)。然后 Leader 会将广播的事务 Proposal 依次添加到 发送队列 中,并且根据 FIFO 策略进行消息发送。保证最终一致性
- 返回应答: 每⼀个 Follower 接收到这个事务 Proposal 之后,都会将其以事务日志的形式写入到本地磁盘中去,然后向 Leader 返回 Ack 进行投票。Observer 不参与投票
- 提交事务: Leader 接收到超过半数 Ack,会给所有的 Follower 广播⼀个 COMMIT 消息进行事务提交,给所有的 Observer 广播 INFORM 消息进行提交,同时 Leader 也会进行事务提交
随着 zookeeper 的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。
4. ZAB 与 Paxos 的异同
相同点:
- 都存在⼀个类似于 Leader 进程的角色,由其负责协调多个 Follower 进程的运行
- Leader 进程都会等待超过半数的 Follower 做出正确的反馈后,才会将⼀个提议进行提交
- 在 ZAB 协议中,每个 Proposal 中都包含了⼀个 epoch 值,用来代表当前的 Leader 周期。在 Paxos 算法中为 Ballot
不同点: ZAB 协议主要⽤于构建⼀个⾼可⽤的分布式数据主备系统,Paxos 算法则⽤于构建⼀个分布式的⼀致性状态机系统
- Paxos 算法中,新选举产⽣的主进程会进⾏两个阶段的⼯作,第⼀阶段称为读阶段,新的主进程和其他进程通信来收集主进程提出的提议,并将它们提交。第⼆阶段称为写阶段,当前主进程开始提出自己的提议。
- ZAB 协议在 Paxos 基础上添加了同步阶段。新选出的 Leader 会确保存在过半的 Follower 提交
了之前接收到的所有事务 Proposal。这⼀同步阶段的引入,能够有效地保证 Leader 在新的周期中提出事务 Proposal 之前,所有的进程都已经完成了对之前所有事务 Proposal 的提交