Zookeeper集群的崩溃恢复

Zookeeper可以帮我们实现服务的注册与发现。然而,现在有一个问题是,如果只采用一个Zookeeper服务器,那么当这个服务器宕机时,意味着整个分布式服务无法正常工作。为了解决这一问题,就需要Zookeeper集群。

然而,在使用Zookeeper集群时,也存在着一个问题,即集群中数据一致性的维护。
Zookeeper集群的崩溃恢复
如上图所示,Zookeeper集群是一主多从结构。

  1. 在更新数据时,首先更新到主服务节点,再更新到从服务节点;
  2. 在读数据时,直接读取任意从服务节点;
  3. 为了保证从节点的数据一致性,Zookeeper采用ZAB协议,类似于一致性算法Paxos和Raft。

ZAB解决了集群崩溃恢复主从数据同步两个问题。

1. 集群崩溃恢复

服务节点共有三种状态:

  1. Looking:选举状态;
  2. Following:从服务节点状态;
  3. Leading:主服务节点状态。

选举过程

当主服务节点宕机时,从从服务节点中选举主服务节点。

  1. 集群中的服务节点各自向其他节点发起投票,投票当中包含自己的服务器ID和最大ZXID(自增事务ID);

  2. 节点会用自身的ZXID和从其他服务节点接收到的ZXID做比较。如果发现其他节点的ZXID比自己的大,也就是数据比自己新,那么久重新发起投票,投票给目前已知的最大ZXID所属的服务节点;

  3. 每次投票之后,服务器都会统计投票数量,判断是否某个服务节点得到半数或以上的投票,如果存在这样的节点,该节点将成为准Leader,状态变为Leading,其他节点的状态变为Following。

发现阶段

通过上述选举阶段后,为了防止网络等原因而发生的意外的情况,也就是说,可能出现多主节点的情况。这种情况会发生写写冲突,为了避免这种情况,Leader集思广益,接收所有的Follower发来的各自最新的epoch值,Leader从中选出最大的epoch,并基于此值加1,生成的新的epoch分发给各个Follower。

各个Follower接收到全新的epoch后,返回ACK给Leader,并带上各自最大的ZXID和历史事务日志。Leader选出最大的ZXID,并更新自身的历史日志,以保持数据最新。

同步阶段

把Leader收到的最新历史事务日志同步给集群中所有的Follower,只有当半数Follower同步成功,这个准Leader才能成为正式的Leader。

2. 主从数据同步

ZAB的数据写入涉及到Broadcase阶段,即Leader广播到所有的Follower,其过程如下:
Zookeeper集群的崩溃恢复

  1. 客户端发出写入数据请求给任意的Follower(服务注册);
  2. Follower把写入数据请求转发给Leader(读写分离,读节点不负责写,只有主节点能够写入);
  3. Leader采用两阶段提交的方式,先发送Propose广播给Follower(先保留提交日志,后执行更新,类似于事务);
  4. Follower接收到Propose消息,写入日志成功后,返回ACK给Leader(开启事务);
  5. Leader接收到半数以上的ACK消息,返回成功给客户端,并且广播Commit请求给Follower(提交事务,可以进行数据持久化)。

数据一致性有三种:强一致性、弱一致性和顺序一致性。而Zookeeper属于顺序一致性。