目录
ZooKeeper 是一个分布式协调服务,广泛应用于分布式系统中。ZooKeeper 可以通过集群(由多个节点组成)来提供高可用性和一致性。以下使其集群启动过程及故障恢复过程。
一、ZooKeeper 集群启动过程
ZooKeeper 集群的启动过程包括多个步骤,从节点初始化到领导者选举,再到集群正式提供服务。下面将逐步讲解这一过程。
1. 节点初始化
每个 ZooKeeper 节点(Server)在启动时,会执行以下初始化操作:
- 读取配置文件:节点从配置文件(通常为
zoo.cfg
)中读取必要的配置信息,例如服务器列表(server.n
)、数据目录、客户端端口等。 - 加载数据:节点会从其数据目录中(配置文件中dataDir和dataLogDir属性配置的路径)加载之前保存的数据和快照(如果存在),包括事务日志(在zookeeper中所有的写操作都被称为事务,和数据库中事务的概念不一样)和数据快照。这些数据帮助节点在启动时恢复之前的状态。
- 读取
myid
文件:每个节点都有一个唯一的 ID,存储在myid
文件中,myid文件位于数据目录下。该 ID 用于区分集群中的各个节点。配置文件中server.n=ip:port:port中的n就对应着myid文件中的数字。
2. 进入 Looking 状态
当 ZooKeeper 节点启动并完成初始化后,它会进入 Looking
状态。这意味着节点正在寻找一个领导者,或者准备参与领导者的选举。
3. 领导者(Leader)节点选举
在Zookeeper集群中的节点有以下几种角色:
- Leader:负责处理所有写请求并确保一致性。
- Follower:接收 Leader 的指令,响应客户端的读请求,并将客户端的写请求转发给Leader。
- Observer:不参与写操作的投票,只用于扩展读请求的服务能力。
其中Observer没有选举权利,选举投票依赖于Follower节点,选举过程如下:
- 节点投票:每个节点都会投票给自己为leader,并向其他节点广播自己的投票信息,投票信息包括节点的
zxid
(事务ID)和myid
(节点ID)。zxid为64位的标识符
前32位为epoch(纪元),当一个节点被选举为leader节点时,则会将这个leader节点的epoch增加。
后32位为事务id,每处理一次事务就会进行一次递增,两者在节点第一次启动时都为0
换句话说,只有当过leader的节点,zxid才会不为0。
- 接收和比较投票:每个节点广播自己的投票结果的同时,也会接收到其他节点的投票,然后会将这些投票信息和自己的投票进行比较,选择最优的节点,重新投票并广播投票信息,规则如下:
- 首先比较
epoch
,epoch
大的节点表示最近的领导者更“新”。 - 如果
epoch
相同,则比较事务id,事务id大的节点表明其处理的事务更多。 - 如果
zxid
也相同,则比较myid
,myid
大的节点优先成为领导者。
- 首先比较
- 达成一致:经过多轮投票,当某个节点获得集群中既定数量(配置文件中配置的quorum)节点的支持时,它将被选为领导者。
- 通知集群:新领导者会通知其他节点,自己已成为领导者,并开始领导集群。
在实际的启动集群过程的领导者选举中,领导者通常由前quorum个启动的节点中决定,因为zookeeper并没有提供一键启动的功能,所以当第quorum个节点启动时选票就已经足够选举出一个leader节点了,等到之后的节点启动时,发现已经有了leader节点,他们就会变成follower节点,同步leader节点的数据。
理论上来说所有节点都在广播自己的投票,那么所有节点比较的都是相同的节点信息,择优选出来的节点应该都是相同的,不应该在第二轮时就会确定最终的leader节点吗?为什么需要多轮呢?
实际上的zookeeper集群是部署在多个主机上的,多个主机之间通讯是存在网络延迟的,由于网络延迟或其他原因,一个节点不会同时收到所有节点的广播信息,所以需要多轮投票。
4. 同步与恢复
一旦领导者被选出,集群中的其他节点会与领导者同步数据,以确保所有节点的状态一致。同步完成后,集群进入正常服务状态,领导者负责处理客户端的写请求,跟随者(Follower)节点则处理读取请求。
zookeeper集群中存在三种节点,分别是Observer节点,Follower节点,以及Leader节点,其中Leader节点负责写操作,Follower接收到写操作会转发给Leader节点,而Observer节点则是只处理读操作,不处理写的请求,也没有转发请求的能力,更不会参加Leader选举。
当Leader节点接收到客户端的写操作时,Leader会将生成的事务日志广播给其他Follower节点,Follower节点在完成事务日志记录的写操作,完成数据同步后会返回确认码(ACK)给Leader,当Leader接收到超过quorum个Flollower节点的确认码后,便认为同步操作已经完成,返回成功响应给客户端。
Observer节点不会接收到Leader的广播,Observer是靠自己主动拉取Leader的数据快照来保证数据一致性。
二、ZooKeeper 故障恢复机制
ZooKeeper 的设计确保集群即使在某些节点故障的情况下,仍能保持高可用性。以下是 ZooKeeper 的故障恢复机制详解。
1. 领导者故障
如果 ZooKeeper 集群中的领导者发生故障(如宕机、网络分区等),剩余的 Follower
和 Observer
节点会检测到领导者的失联。此时,所有的 Follower
节点会再次进入 Looking
状态,启动新的领导者选举。
- Observer 节点:不同于Follower节点将写请求转发给Leader节点,Observer节点不处理写请求,不具备转发能力,在leader选举过程中也没有选举权力,虽然也进入 Looking 状态,但它不会参与领导者选举,只会监听新的领导者选举结果。
- 新的领导者选举:与集群启动时的选举过程相同,剩余节点会通过投票选出一个新的领导者。
新领导者选举完成后,集群恢复正常服务。客户端的写请求会自动转发到新选出的领导者节点,Follower
节点继续处理读取请求。
2. Follower 节点故障
当一个 Follower
节点发生故障时,ZooKeeper 集群可以继续正常运行,因为领导者仍然存在。故障的 Follower
节点一旦恢复(如重新启动),它会自动与领导者节点同步数据,并重新加入集群。
- 数据同步:恢复的
Follower
节点会从领导者处获取最新的事务日志和数据快照,确保其状态与集群一致。 - 重新加入集群:数据同步完成后,该
Follower
节点会恢复到正常状态,并继续参与读请求的处理和一致性协议。
重新加入集群的follower节点的数据同步过程类似于redis数据恢复的rbd文件和aof文件结合使用的过程,首先follower节点会接受leader节点发送来的数据快照,这是一个二进制文件,然后在接收leader记录的从数据快照生成时间节点后的所有写操作的事务日志进行恢复最新数据。
3. 集群分区与恢复
在某些情况下,ZooKeeper 集群可能会因为网络问题而发生分区,导致集群被分为多个孤立的子集群。ZooKeeper 的设计确保只有拥有法定人数(quorum)的子集群能够继续选举领导者并处理请求。
- 多数法则:ZooKeeper 集群要求法定人数才能进行领导者选举和处理写请求。通常来说,法定人数是集群节点总数的一半加一。
- 分区恢复:当网络分区恢复后,原来失去联系的节点会重新加入集群,并与当前的领导者同步数据,恢复到正常状态。