Zookeeper集群启动过程

预启动

  1. 统一由QuorumPeerMain作为启动类

  2. 读取zoo.cfg配置文件

  3. 创建并启动历史文件清理器DatadirCleanupManager

  4. 判断当前是集群模式还是单机模式

初始化

  1. 创建ServerCnxnFactory,

  2. 初始化ServerCnxnFactory,初始化一个线程,作为整个ServerCnxnFactory的主线程然后在初始化NIO服务器

  3. 创建Zookeeper数据管理器FileTxnSnapLog,

  4. 创建QuorumPeer实例,Quorum是集群模式下特有的对象,是Zookeeper服务器实例的托管者,从集群层面来看QuorumPeer代表了Zookeeper集群中一台服务器,在运行期间它会不断检查当前服务器实例运行的状态。然后根据情况进行Leader选举。

  5. 创建内存数据库ZKDatabase

  6. 初始化QuorumPeer,这里把一些核心组件注册到QuorumPeer,这些核心组件包括FileTxnSnapLog、ServerCnxnFactory和ZKDatabase,同时Zookeeper还会对QuorumPeer配置一些参数,包括服务器地址列表,选举算法和会话超时时间等。

  7. 恢复本地数据库

  8. 启动ServerCnxnFactory主线程

  9. Leader选举

  10. 交互和数据同步(看红色部分)

  11. 创建会话管理器

  12. 初始化Zookeeper的请求处理链

  13. 注册JMX


在Leader选举完成之后会有一个Leader和其他服务器(Follower和Observer 统称Learner学习者)进行交互,大致流程如下:

  1. Leader服务器启动Follower接收器,LearnerCnxAcceptor,来接收所有非Leader服务器的连接

  2. Leader与每一个Learner之间都会有一个LearnerHandler实例对应负载它们之间的消息通信和数据同步

  3. Learner和Leader建立连接后,Learner向Leader注册,就是发送自己的信息给Leader,包括当前服务器的SID和ZXID

  4. Leader解析Learner发来的注册信息,在过半向Leader注册的服务器中找到最大的epoch,然后加1,用于确定当前集群的epoch

  5. Leader发送LEADERINFO给Learner

  6. Learner收到LEADERINFO,解析出epoch和ZXID然后给Leader一个反馈

  7. Leader收到Learner响应之后就开始与其进行数据同步

  8. 启动Leader和Learner服务器,有过半数完成数据同步就可以启动了。


Leader选举

选举原则就是比计较MYID、ZXID,这里我们以3台为例,其实2台也可以完成选举,但是通常集群规模最小是3台

服务器启动期间的选举

Server1   myid:1 zxid:0

Server2   myid:2 zxid:0

Server3   myid:3 zxid:0

  1. 每个服务器都会发出一条投票且都是投给自己,以Server1为例(1,0),把这个信息发送到集群中其他服务器上。当然它自己也会收到别人的投票信息

  2. 每个服务器收到其他服务器的投票,先会检查有效性包括检查是否是本轮投票以及是否来自LOOKING状态的服务器发出的

  3. 处理投票,首先比较ZXID,值最大的为Leader,如果值一样那么就比较myid,myid最大的为Leader,Server1会收到(1,0)(2,0)(3,0)经过比较自己的myid不是最大的,它会重新投票新的投票(3,0)并从新发到集群中去,对于Server2也一样,对于Server3来说它不用更新投票信息它比较后自己就是最大的所有再次发出投自己的票就可以。这样每个机器又会收到2个投票信息,Server1会收到Server2、3发来的(3,0)。

  4. 每次投票服务器都会进行投票统计,判断是否有超过半数机器相同的投票信息,对于这三台服务器来说最终投票结果是(3,0),那么除了Server3之外其他都会收到2张(3,0)的投票,这样在一个3台集群中超过半数投票是投给一个机器的,那么这个机器就是集群的Leader。

  5. 一旦确定了Leader那么就需要设置自己的角色以及改变自己的状态Leader变成LEADING,而Follower就变成FOLLOWING。


服务器运行期间的选举

当集群中的服务器数量发生变化时才会进行重新选举,比如之前的Leader故障或者新加入一台Zookeeper服务器。

我们假设上面的Leader  Server3挂了,然后重新选举

Server1   myid:1 zxid:123

Server2   myid:2 zxid:122

Server3   myid:3 zxid: (宕机)

  1. 当集群感知到Leader挂了,那么所有Follower角色的服务器就转变状态从FOLLOWING变成LOOKING

  2. 每个服务器发出投票Server1会发出(1,123)到集群中,Server2会发出(2,122)到集群中,因为第一轮都是投自己。

  3. 集群中可用服务器收到投票

  4. 投票处理,这里和启动时候使用相同的原则,Server1投票不变因为它的ZXID比Server2的大,所以它再次发一个投自己的票,Server2发现自己的ZXID小所以更新投票信息(1,123)再次发出去

  5. 统计投票信息,最终Server1胜出成为Leader

  6. 改变服务器状态