ZAB协议是zookeeper专门设计的一种支持崩溃恢复的原子广播协议。
zab协议包含两种基本模式:
1,崩溃恢复
2,原子广播
1,崩溃恢复:假如说现在zookeeper及zk的集群中有3台机器,一台leader,两台flower。如果说leader挂了,这时候集群内要重新选举出leader,原来的leader变成了flower。新选出来的leader是根据什么来的呢,那就是zxid,集群内zxid最大的就是新的leader。
zk集群还要有连个原则:1,已经被处理的消息不能丢:当leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行COMMIT 并向连接的客户端返回「成功」。但是如果在各个 follower 在收到 COMMIT 命令前 leader 就挂了,导致剩下的服务器并没有执行都这条消息。
见下图:
这时候zab协议就要确保这条消息请求在集群内的所有机器都能提交commit成功了。
2,被丢弃的消息不能再次出现: 当leader收到了客户端的请求就挂了,只是leader机器本机做了commit,还没有发给其他机器做提交动作。这时候根据zxid重新选举出来了leader,原来的leader变成了flower,新的leader会通知这个flower把刚才那个请求删掉(数据同步时会做的。)。
2:原子广播 :
消息广播的过程实际上是一个简化版本的二阶段提交过程(2pc),leader 接收到消息请求后,将消息赋予一个全局唯一的zxid。leader 为每个 follower 准备了一个 FIFO 队列(通过 TCP协议来实现,以实现了全局有序这一个特点)将带有 zxid
的消息作为一个提案( proposal )分发给所有的 follower。当 follower 接收到 proposal ,先把 proposal 写到磁盘,写入成功以后再向 leader 回复一个 ack。
当 leader 接收到合法数量(超过半数节点)的 ACK 后,leader 就会向这些 follower 发送 commit 命令,同时会在本地执行该消息。当 follower 收到消息的 commit 命令以后,会提交该消息。过半的flower发回了ack,这时候leader就会commit。见下图
上面一直在说zxid,什么叫zxid:
zxid 是 6 4 位,高 3 2 位是 epoch 编号,每经过一次 Leader 选举产生一个新的 leader ,新的 leader会将 e poch 号 1 ,低 3 2 位是消息计数器,每接收到一
条消息这个值 1 ,新 leader 选举后这个值重置为 0. 这样设计的好处在于老的 leader 挂了以后重启,它不会被选举为 leader ,因此此时它的 zxid 肯定小于当前新的leader 。当老的 leader 作为 follower 接入新的 leader后,新的 leader 会让 它将所有的拥有旧的 epoch 号的未被 COMMIT 的 proposal 清除。