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 之间只需要往队列中发消息即可。如果使用同步的方式会引起阻塞,性能要下降很多。