ZAB协议简介:
zab协议是Paxos协议的一个变种。它的全称是 ZooKeeper Atomic Broadcast(Zookeeper原子广播协议)。它是一种特别为ZooKeeper设计的崩溃恢复的原子消息广播算法。ZooKeeper采用一个单一的主进程接受并处理客户端的所有事务请求,并将服务器数据的状态变更以事务Proposal的形式广播到所有的副本进程上去。
ZAB协议包含两种基本的模式:
-
崩溃恢复
-
消息广播
ZAB协议包含三个阶段:
-
阶段1:发现(Leader选举过程)
-
阶段2:同步(数据同步过程)
-
阶段3:广播(正式接受请求过程)
当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时, ZAB 协议就会进入恢复模式并选举产生新的 Leader 服务器。当选举产生了新的Leader 服务器同时集群中已经有过半的机器与该 Leader 服务器完成了状态同步之后,ZAB 协议就会退出恢复模式。
当集群中已经有过半的 Follower 服务器完成了和 Leader 服务器的状态同步,那么整个服务框架就可以进入消息广播模式了。当一台同样遵守 ZAB 协议的服务器启动后加入到集群中时,如果此时集群中已经存在一个 Leader 服务器在负责进行消息广播 , 那么新加入的服务器就会自觉地进入数据恢复模式:找到 Leader 所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。
崩溃恢复
当整个服务器在启动过程中,或者当Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并通过选举产生新的Leader服务器。
-
当选举产生了新的Leader服务器,同时集群中已经有过半机器与该Leader服务器完成状态同步之后,ZAB协议就会退出恢复模式。这里的状态同步指的就是数据同步,用来保证集群中存在过半的机器能够和Leader服务器的数据保持一致。
-
当集群中有过半的Follower服务器完成和Leader服务器的同步,那么整个服务器集群就可以进入消息广播模式。
-
当新的机器加入集群,由于集群已经存在一个Leader,那么新加入的机器会进入数据同步模式,即找到Leader服务器,并与其进行数据同步。
-
当Leader崩溃退出或者重启,或者及集群中不存在过半的服务器可以和Leader保持正常通信,那么在开始新一轮事务操作前所有机器会使用崩溃恢复协议来达到一个一致性的状态。
// 选票和服务器的当前选票进行对比 protected boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch) { LOG.debug("id: " + newId + ", proposed id: " + curId + ", zxid: 0x" + Long.toHexString(newZxid) + ", proposed zxid: 0x" + Long.toHexString(curZxid)); if(self.getQuorumVerifier().getWeight(newId) == 0){ return false; } /* * 以下三种情况成立,则返回true: * 1- 新epoch更大 * 2- 新epoch与当前epoch相同,但新zxid更大 * 3- 新epoch与当前epoch相同,新zxid与当前zxid相同,但是服务器id更高。 */ return ((newEpoch > curEpoch) || ((newEpoch == curEpoch) && ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId))))); }
消息广播
消息广播类似于一个2PC提交过程。根据客户端的事务请求,Leader服务器会为其生成对应的事务投票(即Proposal)并将其发送给集群中其他服务器,然后在分表搜集各自的选票,最后进行事务提交。
与2PC不同的是,ZAB协议没有中断逻辑(所有Follower要么对Leader提成的事务Ack,要么就不回应),而且当过半的Follower服务器反馈Ack之后就开始提交事务,不用等待所有Follower都反馈。
整个消息广播协议是基于FIFO特性的TCP协议来进行网络通信,因此能够很容易地保证消息广播过程中消息接受与发送的顺序性。
-
Leader接收到消息请求后,将消息赋予一个全局唯一的64位自增id,叫做:Zxid,通过zxid的大小比较即可实现因果有序这一特性。
-
Leader通过先进先出队列(通过 TCP 协议来实现,以此实现了全局有序这一特性)将带有zxid的消息作为一个提案(Proposal)分发给所有Follower。
-
当Follower接收到Proposal,先将Proposal写到硬盘,写硬盘成功后再向Leader回一个ACK。
-
当Leader接收到合法数量的ACKs后,Leader就向所有Follower发送COMMIT命令,同时会在本地执行该消息。
-
当Follower收到消息的COMMIT命令时,就会执行该消息。
数据同步
整个集群完成Leader选举后,Learner会向Leader进行注册,当Learner向Leader完成注册后,就进入数据同步环节,同步过程就是Leader将那些没有在Learner服务器上提交过的事务请求同步给Learner服务器。
1、直接差异化同步
适用于Follower节点崩溃恢复
2、先回滚再差异化同步
适用于Leader节点 崩溃后,选举出新的Leader节点并提交了新的事物
3、仅回滚(特殊的先回滚再差异化同步)
适用于Leader节点崩溃后,选举出新的节点,没有事物提交
4、全量同步
适用于有新的Follower 节点加入