ZAB(Zookeeper Aotmic Broadcast)协议是专门为Zookeeper实现分布式协调服务而设计的一种支持崩溃恢复和原子广播协议。基于该协议,Zookeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间数据一致性。ZAB协议只允许有一个主进程(即leader)接收客户端事务请求并进行处理。当leader收到事务请求后,将请求事务转化成事务proposal,由于leader会为每个follower创建一个队列,将该事务proposal放入响应队列,保证事务的顺序性。之后会在队列中顺序向其它节点广播该提案,follower收到后会将其以事务的形式写入到本地日志中,并且向leader发送Ack信息确认,当有一半以上的follower返回Ack信息时,leader会提交该提案并且向其它节点发送commit信息。
ZAB协议包括两种模式:即崩溃恢复模式和消息广播模式。当 Leader 不可用时,(/即当系统启动或者leader服务器出现故障等现象时/),则进入崩溃恢复模式, 将会开启新的一轮选举,选举产生的leader会与过半的follower进行同步,使数据一致。当同步结束后,退出恢复模式,进入消息广播模式。
消息广播模式:ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个二阶段提交过程。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成一个事务 Proposal,将其发送给所有 Follower ,然后,根据所有 Follower 的反馈,如果超过半数成功响应,则执行 commit 操作(先提交自己,再发送 commit 给所有 Follower)。消息广播具体流程图如下:
zookeeper中消息广播的具体步骤如下:
1. 客户端发起一个写操作请求 。
2. Leader服务器将客户端的request请求转化为事物proposql提案/事务,同时为每个proposal分配一个全局唯一的ID,即ZXID。
3. leader服务器与每个follower之间都有一个队列,leader将消息发送到该队列 。
4. follower机器从队列中取出消息处理完毕(写入本地事物日志中,但不提交)后,向leader服务器发送ACK确认。
5. leader服务器收到半数以上的follower的ACK后,leader先提交proposal事务,再发送commit 信息给所有的follower。
注意点:
1. ZAB 协议需要保证事务的顺序,因此必须将每一个事务按照 ZXID 进行先后排序然后处理。
2. 在 Leader 和 Follwer 之间的消息队列,用来解耦他们之间的耦合,解除同步阻塞。
3. zookeeper集群中为保证任何所有进程能够有序的顺序执行,只能是 Leader 服务器接受写请求,即使是 Follower 服务器接受到客户端的请求,也会转发到 Leader 服务器进行处理。
4. 实际上,这是一种简化版本的 2PC,不能解决单点问题。接下来讲述ZAB 如何解决单点问题(即 Leader 崩溃问题)。
崩溃恢复模式:当leader宕机或发生故障,集群中少于一半的节点与当前leader保持连接时,则zab协议要求zookeeper集群进行崩溃恢复(/新的leader服务器选举和数据同步/)。leader服务器发生崩溃的情况有以下两种,1:Leader 在复制数据给所有 Follower 之后崩溃。2:Leader 在收到 Ack 并提交了自己,同时发送了部分 commit 出去之后崩溃。针对这这些情况,ZAB协议崩溃恢复要求满足如下2个要求:1.ZAB 协议确保那些已经在 Leader 提交的事务最终会被所有服务器提交。1.ZAB 协议确保丢弃那些只在 Leader 提出/复制,但没有提交的事务。根据上述要求,新选举出来的leader不能包含未提交的proposal,即新选举的leader必须都是已经提交了的proposal的follower服务器节点。同时,新选举的leader节点中含有最高的ZXID。这样做的好处就是可以避免了leader服务器检查proposal的提交和丢弃工作。
数据同步:选在zookeeper集群中新的leader选举成功之后,leader会将自身的提交的最大proposal的事物ZXID发送给其他的follower节点。follower节点会根据leader的消息进行回退或者是数据同步操作。最终目的要保证集群中所有节点的数据副本保持一致。
实际上,Leader 服务器处理或丢弃事务都是依赖着 ZXID 的,那么这个 ZXID 如何生成呢?
答:在 ZAB 协议的事务编号 ZXID 设计中,ZXID 是一个 64 位的数字,其中低 32 位可以看作是一个简单的递增的计数器,针对客户端的每一个事务请求,Leader 都会产生一个新的事务 Proposal 并对该计数器进行 + 1 操作。
而高 32 位则代表了 Leader 服务器上取出本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,然后再对这个值加一。
高 32 位代表了每代 Leader 的唯一性,低 32 代表了每代 Leader 中事务的唯一性。同时,也能让 Follwer 通过高 32 位识别不同的 Leader。简化了数据恢复流程。
基于这样的策略:当 Follower 链接上 Leader 之后,Leader 服务器会根据自己服务器上最后被提交的 ZXID 和 Follower 上的 ZXID 进行比对,比对结果要么回滚,要么和 Leader 同步。
参考文档:
1.https://my.oschina.net/weiweiblog/blog/3026081
2.https://blog.csdn.net/xiaocai9999/article/details/80641404
3.https://blog.csdn.net/weixin_34452850/article/details/88419394
4.https://my.oschina.net/134596/blog/1647079
来源:oschina
链接:https://my.oschina.net/u/4480939/blog/3207237