ZooKeeper 集群详解(ZK集群的概念/Leader选举机制/ZAB原子广播协议/集群的崩溃恢复/恢复后的数据同步)
ZooKeeper提供了一个类似于Linux文件系统的树形结构,同时提供了对于每个节点的监控与通知机制。
本节将介绍ZooKeeper如何保证集群下的数据一致性,如何进行领导选举,以及数据监控/通知机制的语义保证。
为什么需要集群
- 为了提供可靠的ZooKeeper服务
- 超过半数服务器准备就绪,就可以对外提供服务
- 集群高可用设置至少需要三个服务器,建议使用奇数个服务器。如果只有两台服务器,那么您将处于一种情况,如果其中一台服务器发生故障,则没有足够的计算机构成多数仲裁。由于存在两个单点故障,因此两个服务器本来就不如单个服务器稳定。
ZAB原子广播协议
简介
- ZAB协议(ZooKeeper Atomic Broadcast , ZooKeeper原子消息广播协议)是为了保证写操作的集群一致性设计的,支持崩溃恢复的一致性协议。
- 基于该协议,ZooKeeper实现了一种主从模式的系统架构来保持集群中各个副本之间的数据一致性。
有序性
ZAB 协议的重要特性之一是有序性,它保证写操作的一致性
- 集群中,所有的写请求都会被转发到 Leader
- Leader 生成 Zxid(全局递增的事务ID),并发出 Propose
- Follower 处理 Propose,并通知 Leader
- Leader 收到半数以上的反馈,发出 Commit
- Leader 做出相应
崩溃恢复
ZAB协议保证了 Failover 过程中的数据一致性
如何保证恢复后的一致性
leader 崩溃,或与半数 follower失去同步(syncLimit),则集群进入崩溃恢复模式
- ZAB 协议保证了,在 leader失去同步的情况下, 如果一个事务 proposal 在一台机器上被处理成功,则故障恢复时,会在集群所有机器上被处理。
- 被 commit 的事务,在崩溃恢复时会被最终提交
- 仅仅被 proposal 但没有 commit 的事务,在崩溃恢复时会被丢弃
恢复后的数据同步
Leader选举出来后,需完成Followers 与Leader的数据同步,当半数的Followers完成同步,则可以开始提供服务。
同步的过程如下:
- leader 会为每一个 follower 准备一个同步队列
- leader 将那些没有被各 follower 同步的事务以 Proposal 消息的形式逐个发送给 follower
- leader 会在每一个 proposal 消息后,立即发送一个 commit 消息,以表示该事务已经被提交
- follower 同步完所有的 proposal 后,leader 就会将该 follower 加入到真正的可用 follower 列表中,并开始之后的其他流程。
丢弃无效Proposal
- 当一个包含了上一个 leader 周期中,尚未 coomit 的 proposal 的 follower 连入集群时,leader 会要求 follower 将其 zxid_set 中大于 follower 的 max_zxid(如果有)的所有消息全部删除
Zxid的生成策略
在 ZAB 协议的事务编号 Zxid 设计中,ZXID 是一个 64 位的数字。
- 低32位是一个简单的单调递增的计数器。针对客户端的每一个事务请求,leader 在产生一个新的事务 Proposal 的时候,都会对该计数器进行加1操作
- 高32位是 leader 周期纪元的编号。每当选举产生一个新的 leader,就会从这个 leader 的本地日志中,取出max_zxid,并从该 zxid 中解析出对应的纪元值,对其进行加1操作后,以此编号作为新的纪元值。
- 此时,低 32 位会被置零
选举
基础概念
myid
- 简单来说就是服务器ID
- ZooKeeper集成中的每台计算机都应该知道该集成中的其他每台计算机。通过为服务器创建一个名为 myid 的文件,将服务器ID分配给每台计算机,该文件位于配置文件参数 dataDir 指定的该服务器数据目录中。
Zxid
- 具有全局一致性的事务ID
- 对于 ZK 数据的每次更改,都会生成一个全局唯一的Z Zxid
- Zxid 具有顺序性,如果 zxid1 小于 zxid2,则 zxid1 在 zxid2 之前发生
逻辑时钟
- 用于标识投票的轮数
- 当第一次选举没有选出 Leader 时,会发起第二轮选举
选举状态
竞选 Leader 时,发送到集群的信息中所包含的数据
- Looking:正在竞选状态
- Following:跟随态,同步 leader 的状态,参与投票
- Observing:观察态,同步 leader 的状态,不参与投票
- 集群较大时会出现
- 当集群较大时,并非所有的节点都参与选举,全部节点都参与选举会效率较低且消耗资源
- Leading:领导者
Leader选举
选举要求
- 选出的 leader 节点上要持有最高的 zxid
- 过半数节点同意
选举算法
- 基于UDP的LeaderElection
- 基于UDP的FastLeaderElection(默认)
- 基于UDP和认证的FastLeaderElection
- 基于TCP的FastLeaderElection
选举流程
- 每一台参与选举的 server 在发起选举时,都会拥有一票赞成票(自己投的)
- 投票:发起者会发起投票邀请
- 其他 server 收到邀请后,会比较两台 server 的 zxid,如果自己的 zxid 发起者的 zxid,则投赞成票。
- 如果 zxid 相同,则比较两者的 myid
- 统计:发起者收到反馈后,会进行统计
- 如果票数大于集群机器数的一半,则成为 leader
- 如果未超过半数,且 leader 未选出,则重新发起投票
胜出条件
- 某一台参与选举的机器,获得了一半以上的票数
选举过程
有5台 server ,每台 server 均没有数据,它们的编号分别是 1/2/3/4/5 按编号依次启动,它们的选举过程如下
- server1 启动,给自己投票,然后发投票信息。由于其它机器还没有启动所以它收不到反馈信息,server1 的状态一直属于 Looking。
- server2 启动,给自己投票,同时与之前启动的 server1 交换结果。由于 server 2 的编号大,所以 server 2 胜出。但此时投票数没有大于半数,所以两个服务器的状态依然是 Looking
- server3 启动,给自己投票,同时与之前启动的 server1/server2 交换信息。由于 server3 的编号最大所以 server3 胜出,此时投票数正好大于半数,所以服务器3成为 leader,server1/server2 成为 follower
- server4 启动,给自己投票,同时与之前启动的 server1/server2/server3 交换信息,尽管 server4 的编号大,但之前 server3 已经胜出,所以 server只能成为 follower
- server5 启动,后面的逻辑同 server4 成为 flollower
集群搭建和监控
搭建
监控