转载: Zookeeper 一致性协议原理 Zab https://www.cnblogs.com/hongdada/p/8145075.html
ZooKeeper 为高可用的一致性协调框架, 自然的 ZooKeeper 也有着一致性算法的实现, ZooKeeper 使用的是 ZAB 协议作为数据一致性的算法, ZAB(ZooKeeper Atomic Broadcast ) 全称为: 原子消息广播协议;
ZAB 可以说是在 Paxos 算法基础上进行了扩展改造而来的, ZAB 协议设计了支持崩溃恢复, ZooKeeper 使用单一主进程 Leader 用于处理客户端所有事务请求, 采用 ZAB 协议将服务器数状态以事务形式广播到所有 Follower 上;
由于事务间可能存在着依赖关系, ZAB 协议保证 Leader 广播的变更序列被顺序的处理,: 一个状态被处理那么它所依赖的状态也已经提前被处理;
ZAB 协议支持的崩溃恢复可以保证在 Leader 进程崩溃的时候可以重新选出 Leader 并且保证数据的完整性;
在 ZooKeeper 中所有的事务请求都由一个主服务器也就是 Leader 来处理, 其他服务器为 Follower,Leader 将客户端的事务请求转换为事务 Proposal, 并且将 Proposal 分发给集群中其他所有的 Follower, 然后 Leader 等待 Follwer 反馈, 当有 过半数 (>=N/2+1) 的 Follower 反馈信息后, Leader 将再次向集群内 Follower 广播 Commit 信息, Commit 为将之前的 Proposal 提交;
ZooKeeper 从以下几点保证了数据的一致性
1 顺序一致性
来自任意特定客户端的更新都会按其发送顺序被提交. 也就是说, 如果一个客户端将 Znode z 的值更新为 a, 在之后的操作中, 它又将 z 的值更新为 b, 则没有客户端能够在看到 z 的值是 b 之后再看到值 a(如果没有其他对 z 的更新).
2 原子性
每个更新要么成功, 要么失败. 这意味着如果一个更新失败, 则不会有客户端会看到这个更新的结果.
3 单一系统映像
一个客户端无论连接到哪一台服务器, 它看到的都是同样的系统视图. 这意味着, 如果一个客户端在同一个会话中连接到一台新的服务器, 它所看到的系统状态不会比在之前服务器上所看到的更老. 当一台服务器出现故障, 导致它的一个客户端需要尝试连接集合体中其他的服务器时, 所有滞后于故障服务器的服务器都不会接受该连接请求, 除非这些服务器赶上故障服务器.
4 持久性
一个更新一旦成功, 其结果就会持久存在并且不会被撤销. 这表明更新不会受到服务器故障的影响.
==========================================================================
ZAB 协议的两个基本模式: 恢复模式和广播模式
恢复模式:(选举)
当服务启动或者在领导者崩溃后, Zab 就进入了恢复模式, 当领导者被选举出来, 且大多数 server 完成了和 leader 的状态同步以后, 恢复模式就结束了. 状态同步保证了 leader 和 server 具有相同的系统状态.
具体选举看下面文章
崩溃恢复过程中, 为了保证数据一致性需要处理特殊情况:
1, 已经被 leader 提交的 proposal 确保最终被所有的服务器 follower 提交
2, 确保那些只在 leader 被提出的 proposal 被丢弃
针对这个要求, 如果让 leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高的 ZXID 事务 proposal, 就可以保证这个新选举出来的 Leader 一定具有所有已经提交的提案, 也可以省去 Leader 服务器检查 proposal 的提交与丢弃的工作.
广播模式:(数据同步)
一旦 Leader 已经和多数的 Follower 进行了状态同步后, 他就可以开始广播消息了, 即进入广播状态.
这时候当一个 Server 加入 ZooKeeper 服务中, 它会在恢复模式下启动, 发现 Leader, 并和 Leader 进行状态同步. 待到同步结束, 它也参与消息广播.
ZooKeeper 服务一直维持在广播状态, 直到 Leader 崩溃了或者 Leader 失去了大部分的 Followers 支持.
广播模式极其类似于分布式事务中的 2pc(two-phrase commit 两阶段提交): 即 Leader 提起一个决议, 由 Followers 进行投票, Leader 对投票结果进行计算决定是否通过该决议, 如果通过执行该决议 (事务), 否则什么也不做.
广播协议在所有的通讯过程中使用 TCP 的 FIFO 信道, 通过使用该信道, 使保持有序性变得非常的容易. 通过 FIFO 信道, 消息被有序的 deliver. 只要收到的消息一被处理, 其顺序就会被保存下来.
Leader 会广播已经被 deliver 的 Proposal 消息. 在发出一个 Proposal 消息前, Leader 会分配给 Proposal 一个单调递增的唯一 id, 称之为 zxid.
广播是把 Proposal 封装到消息当中, 并添加到指向 Follower 的输出队列中, 通过 FIFO 信道发送到 Follower.
当 Follower 收到一个 Proposal 时, 会将其写入到磁盘, 可以的话进行批量写入. 一旦被写入到磁盘媒介当中, Follower 就会发送一个 ACK 给 Leader.
当 Leader 收到了指定数量的 ACK 时, Leader 将广播 commit 消息并在本地递交该消息. 当收到 Leader 发来 commit 消息时, Follower 也会递交该消息.
ZAB 协议简化了 2PC 事务提交:
1, 去除中断逻辑移除, follower 要么 ack, 要么抛弃 Leader;
2,leader 不需要所有的 Follower 都响应成功, 只要一个多数派 ACK 即可.
丢弃的事务 proposal 处理过程:
ZAB 协议中使用 ZXID 作为事务编号, ZXID 为 64 位数字, 低 32 位为一个递增的计数器, 每一个客户端的一个事务请求时 Leader 产生新的事务后该计数器都会加 1,
高 32 位为 Leader 周期 epoch 编号, 当新选举出一个 Leader 节点时 Leader 会取出本地日志中最大事务 Proposal 的 ZXID 解析出对应的 epoch 把该值加 1 作为新的 epoch, 将低 32 位从 0 开始生成新的 ZXID;
ZAB 使用 epoch 来区分不同的 Leader 周期, 能有效避免了不同的 leader 服务器错误的使用相同的 ZXID 编号提出不同的事务 proposal 的异常情况, 大大简化了提升了数据恢复流程;
所以这个崩溃的机器启动时, 也无法成为新一轮的 Leader, 因为当前集群中的机器一定包含了更高的 epoch 的事务 proposal.
来源: http://www.bubuko.com/infodetail-2931781.html