ZAB介绍
ZooKeeper Atomic Broadcast(ZooKeeper原子广播协议),用来保证分布式事务的最终一致性。
它是CAP理论中CP的实现(发生网络分区后,少数节点的分区无法选举出主节点,导致这部分节点上的写请求无法被处理)。由于其允许Follower节点读取数据(同时返回该节点上最大的ZXID),所以它并不能满足强一致性,保证的是最终一致性(顺序一致性:先提交的请求先被查询到)。
可以看到ZAB和Raft协议非常类似,其舍弃了Raft协议强一致性的设计,提供Follower节点也能处理查询请求的能力,一定程度上提高了系统的可用性和性能,并优化了选主算法。
选主
ZK默认并建议的选主算法是:基于TCP的FastLeaderElection,它涉及几个重要的参数:
- 服务器ID(myid): 每个zookeeper服务器,都要在数据文件夹下创建一个名为myid的文件,存储当前节点在集群中的ID(整数),选举时如果无法根据其它条件选择Leader,则根据ID大小确认优先级。
- 事务ID(ZXID): 单调递增,值越大说明数据越新,则其权重越大。
- 逻辑时钟(Logic Clock): 用来标识投票伦次。
ZAB协议定了了节点有三种状态
- Looking: 节点启动后默认处于这种状态,会给自己投一票,广播出去并处理其它节点的响应。同时也要处理其它节点的投票信息广播。
- Leading: 节点收到多数节点的投票后,则变更到Leading状态
- Following: 跟随状态,接收主节点的复制数据。
对于一个新的集群,默认情况下Z=0, L=1;节点启动后处于Looking状态,投自己一票,并将自己的投票广播出去。接收到投票广播后,存储自己的投票池,并判断是否要把投给自己的票更改,如果发生更改则继续广播,对于新集群来说,较大myid的服务器最有可能被选为Leader(也跟启动顺序有关)。
对于一个非全新集群,则先比较ZXID,大的胜出;ZXID相同的情况下,myid大的胜出。
由于集群节点启动有先后顺序,新集群启动选举过程中,不一定是myid最大的节点,但一定是myid较大的节点胜出。
读写数据
ZAB协议对Raft协议进行了改造,Follower节点接收到的读请求可以直接处理,写请求需要转发给主节点处理,主节点生成一个事务请求(分配一个ZXID),并广播出去进行协调,当收到大多数节点同意后,leader会通知所有节点进行commit,将这次写操作应用到内存数据库中,并记录到事务日志中。
当事务日志达到一定数量(默认10万次),会将内存数据库序列化一次到快照文件中(Snapshot),清理掉旧的事务日志。后续可以通过快照文件+新的事务日志恢复节点。