概念
ZAB(ZooKeeper Atomic Broadcast,原子广播协议),解决zk的奔溃恢复和主从数据同步问题。
集群的三种角色
Zookeeper 集群是一个基于主从复制的高可用集群,每个服务器承担如下三种角色中的一种
Leader
- 一个 Zookeeper 集群同一时间只会有一个实际工作的 Leader,它会发起并维护与各 Follwer 及 Observer 间的心跳。
- 所有的写操作必须要通过 Leader 完成再由 Leader 将写操作广播给其它服务器。只要有超过半数节点(不包括 observeer 节点)写入成功,该写请求就会被提交(类 2PC 协议)。
Follower
- 一个 Zookeeper 集群可能同时存在多个 Follower,它会响应 Leader 的心跳,
- Follower 可直接处理并返回客户端的读请求,同时会将写请求转发给 Leader 处理,并且负责在 Leader 处理写请求时对请求进行投票。
Observer
- 角色与 Follower 类似,但是无投票权。Zookeeper 需保证高可用和强一致性,为了支持更多的客户端,需要增加更多 Server;Server 增多,投票阶段延迟增大,影响性能;引入 Observer, Observer 不参与投票; Observers 接受客户端的连接,并将写请求转发给 leader 节点; 加入更多 Observer 节点,提高伸缩性,同时不影响吞吐率。
集群节点的四种状态
- Looking:选举中状态,当前集群无leader
- Following:Follower节点所处的状态
- Leading:Leader(主节点)所处的状态
- Observing:Observer所处的状态
ZAB协议的两种模式
- 选举模式。当主节点宕机重新选举或者集群刚启动时,处于选举模式。
- 广播模式。主节点写入数据后,需要同步数据到其它节点,这时候处于广播模式。
核心概念:
Zxid:称为事务ID,节点内的每次数据更新操作都会让Zxid+1。
myid:节点ID,ZK集群的唯一标识,设置在配置文件中。
投票:本质上是一次网络通信的过程,发送自己的投票结果,包含三个维度信息(myid,投给谁,自己最新的事务ID)
投票箱:实际上是一个数组,记录本节点收到的所有投票记录,每个记录包含三个维度信息(谁的投票(ID),投给谁,被投方的最新事务ID)。
选举模式
基本规则:投票过程,先比较Zxid事务ID,大的赢的当前票(数据最新)。如果相同,比较myid,大的赢得选票。最后保存本次选票结果,并将选票结果通过网络通信告知其他节点,其它节点也会给每个节点保存一份投票结果。最终得票最多的节点当选leader。
举个例子,zk集群配置文件配置了三个节点。逐一启动三个节点。
开始每个节点都会给自己投票,启动到第二个节点时,两个节点都各得一票:
zk1发现zk2启动了,互相发送网络请求,告知对方自己的投票结果。此时zk1发现zk2的事务ID和自己一样,都是100,但是zk2的myid比自己大,于是把自己的票投给了zk2,记录在各自的投票箱。因为集群中有三个节点,此时zk2赢得两张投票,不需要等zk3起来,就当选了leader。
广播模式
本质上是一种2PC的过程。每个节点都可以接收到客户端的写请求,如果不是leader,则把该请求交给leader处理。leader内部维护了一个队列,会把写请求入队,一个一个处理。
举例说明leader处理一次写请求的过程。
- leader接收到一个写请求,先生成日志,Zxid+1
- 持久化日志,防止数据丢失
- 预提交阶段,将最新写数据同步给其它节点,等待其它节点的ack响应
- 从节点收到主节点的同步请求后,先持久化,再响应leader一个ack报文
- 当收到超过半数ack响应时,将数据更新到内存的DataTree对象中,并发送commit命令
- 从节点收到commit命令后,也将数据更新到DataTree对象中,至此,一次数据写入过程完成。
- leader异步发送同步请求给Observer节点。