本文作者:HelloGitHub-老荀
Hi,这里是 HelloGitHub 推出的 HelloZooKeeper 系列,免费开源、有趣、入门级的 ZooKeeper 教程,面向有编程基础的新手。
项目地址:https://github.com/HelloGitHub-Team/HelloZooKeeper
前一篇文章我们介绍了 ZK 是如何进行持久化的,这章我们将正式学习 Follower 或 Observer 是如何在选举之后和 Leader 进行数据同步的。
一、选举完成经历了选举之后,我们的马果果荣耀当选当前办事处集群的 Leader,所以现在假设各个办事处的关系图是这样:
我们现在就来说说马小云和马小腾是如何同马果果进行数据同步的。
结束了累人的选举后,马小云和马小腾以微弱的优势输掉了竞争,只能委屈成为 Follower。整理完各自的情绪后,他们要做的第一件事情就是通过话务员上报自己的信息给马果果,使用了专门的暗号 FOLLOWERINFO, 数据主要有自己的 epoch 和 myid:
然后是马果果这边,他收到 FOLLOWERINFO 之后也会进行统计,直到达到半数以上后,综合各个 Follower 给的信息会计算出新的 epoch,然后将这个新的 epoch 随着暗号 LEADERINFO 回发给其他 Follower
然后再回到马小云和马小腾这边,收到 LEADERINFO 之后将新的 epoch 记录下来,然后回复给马果果一个 ACKEPOCH 暗号并带上自己这边的最大 zxid,表示刚刚的 LEADERINFO 收到了
然后马果果这边也会等待半数以上的 ACKEPOCH 的通知,收到之后会根据各个 Follower 的信息给出不同的同步策略。关于不同的同步策略,这里我先入为主的给大家介绍一下:
DIFF,如果 Follower 的记录和 Leader 的记录相差的不多,使用增量同步的方式将一个一个写请求发送给 Follower
TRUNC,这个情况的出现代表 Follower 的 zxid 是领先于当前的 Leader 的(可能是以前的 Leader),需要 Follower 自行把多余的部分给截断,降级到和 Leader 一致
SNAP,如果 Follower 的记录和当前 Leader 相差太多,Leader 直接将自己的整个内存数据发送给 Follower
至于采用哪一种策略,是如何进行判断的,接下来一一进行讲解。
1.1 DIFF每一个 ZK 节点在收到写请求后,会维护一个写请求队列(默认是 500 大小,通过 zookeeper.commitLogCount 配置),将写请求记录在其中,这个队列中的最早进入的写请求当时的 zxid 就是 minZxid(以下简称 min),最后一个进入的写请求的 zxid 就是 maxZxid(以下简称 max),达到上限后,会移除最早进入的写请求,知道了这两个值之后,我们来看看 DIFF 是怎么判断的。
1.1.1 从内存中的写请求队列恢复一种情况就是如果当 Follower 通过 ACKEPOCH 上报的 zxid 是在 min 和 max 之间的话,就采用 DIFF 策略进行数据同步。
我们的例子中 Leader 的 zxid 是 99,说明这个存储 500 个写请求的队列根本没有放满,所以 min 是 1 max 是 99,很显然 77 以及 88 是在这个区间内的,那马果果就会为另外两位 Follower 找到他们各自所需要的区间,先发送一个 DIFF 给 Follower,然后将一条条的写请求包装成 PROPOSAL 和 COMMIT 的顺序发给他们
1.1.2 从磁盘文件 log 恢复