Zookeeper 简介
Zookeeper 为分布式应用提供了一个高效可靠的分布式协调服务。实现依赖于 ZAB 协议,实现了一种主备模式的架构来保持集群中数据的一致性。Zookeeper 使得分布式应用可以通过一个共享的树形结构的命名空间实现协调。Zookeeper 的所有数据都存储再内存中。Zookeeper 集群中的任何一台机器都可以响应客户端的读操作,且全量数据存储在内存中,因此 Zookeeper 更适合以读操作为主的应用场景。
集群中包含三种角色:leader、follower、observer
lerader:leader 是通过选举确定的一台机器,为客户端提供读写功能。
follower 和 observer 提供读功能,不同的是 observer 不参与选举,也不参与半写成功策略,因此 observer 可以在不影响写性能的前提下提升集群的读性能。
当 follower 节点接收到读请求时可以直接从本地副本数据库中直接返回,可如果得到的是写请求则需要通过一致性协议来解决,因此增加 follower 节点只能增加读性能不能增强写性能,这也是 observer 节点出现的原因
Zookeeper 集群节点中参与选举的节点为奇数个,zookeeper 的节点分为临时节点、持久节点、顺序节点,节点上最重要的就是 watcher 功能,客户端可以在节点上设置watch,我们称之为监视器。当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次,这样可以减少网络流量。
ZAB 协议
ZAB 协议是为 Zookeeper 专门设计的一种支持崩溃恢复的消息广播协议。ZAB 协议只允许有一个主进程接收客户事务请求并处理,即 leader。当 leader 收到请求后将请求事务转化为事务 proposal,由于 leader 会为每一个 follower 创建一个队列,将该事务放入响应队列,还在每个事务上附加了 zxid 来保证事务的顺序性,zxid 按照事务的顺序递增,因此可以记录事物的先后顺序。之后会在队列中顺序地向其他节点广播该提案,follower 收到后会将其以事务的形式写入到本地日志中,并向 leader 发送反馈 ack。leader 会等待其他 follower 的回复,当收到超过半数 follower 的响应时,leader 会向其他节点发送 commit 消息,要求其余节点返回上一条事务。
ZAB 有两种模式:故障恢复模式和消息广播模式
- 故障恢复模式
当系统启动或者 leader 服务器出现故障等现象时进入故障恢复模式,将会开启新一轮选举。选举产生的 leader 会与过半的 follower 进行同步,使数据一致。当同步结束后,退出恢复模式,进入消息广播模式。当一台遵守 ZAB 协议的服务器启动后,如果检测到有 leader 在广播消息,会自动进入恢复模式,当其完成与 leader 的同步后,自己也会进入广播模式。
选举 leader 时会对各节点中最大的 zxid 进行比较,最终选出拥有全局最大 zxid 的节点作为 leader,由于 zxid 是按照事务的先后顺序依次递增的,因此拥有的 zxid 越大就代表其保存的事务集合越完整
zxid 是一个 64 位的数字,高 32 位为 epoch,用以区分不同 leader 的事务,以避免旧 leader 的影响,因为 follower 只接受最大 epoch 的事务。低 32 位为当前 leader 事务计数
当 leader 选举完成时,获胜节点会成为准 leader 并进行数据同步,数据同步完成后才能真正履行 leader 的职责。同步时将各个事务写入对应 follower 的队列,当 follower 完成所有事务的同步后才能加入可用 follower 列表
leader 重新选举的条件:leader 宕机或发生故障,集群中少于一半的节点与当前 leader 保持连接
- 消息广播模式
1)客户端发起一个写操作请求。
2)Leader 服务器将客户端的请求转化为事务 Proposal 提案,同时为每个 Proposal 分配一个全局的ID,即zxid。
3)Leader 服务器为每个 Follower 服务器分配一个单独的队列,然后将需要广播的 Proposal 依次放到队列中取,并且根据 FIFO 策略进行消息发送。
4)Follower 接收到 Proposal 后,会首先将其以事务日志的方式写入本地磁盘中,写入成功后向 Leader 反馈一个 Ack 响应消息。
5)Leader 接收到超过半数以上 Follower 的 Ack 响应消息后,即认为消息发送成功,可以发送 commit 消息。
6)Leader 向所有 Follower 广播 commit 消息,同时自身也会完成事务提交(数据更新)。Follower 接收到 commit 消息后,会将上一条事务提交(数据更新)。
zookeeper 采用 Zab 协议的核心,就是只要有一台服务器提交了 Proposal,就要确保所有的服务器最终都能正确提交 Proposal。这也是 CAP/BASE 实现最终一致性的一个体现。
Leader 服务器与每一个 Follower 服务器之间都维护了一个单独的 FIFO 消息队列进行收发消息,使用队列消息可以做到异步解耦。 Leader 和 Follower 之间只需要往队列中发消息即可。如果使用同步的方式会引起阻塞,性能要下降很多。