文章目录

  • Zookeeper 服务器启动过程
  • zookeeper服务端整体架构图
  • 单机版服务器启动过程
  • 预启动
  • 初始化
  • 集群服务器启动过程
  • 预启动
  • 初始化
  • Leader 选举
  • Leader 和 Follower 启动期交互过程
  • Leader 和 Follower 启动


Zookeeper 服务器启动过程

zookeeper服务端整体架构图

zookeeper注册服务挂了 zookeeper 服务器状态_服务器

zookeeper 服务器的启动,大致可以分为以下五个步骤:

  1. 配置文件解析
  2. 初始化数据管理器
  3. 初始化网络I/O管理器
  4. 数据恢复
  5. 对外服务

单机版服务器启动过程

zookeeper注册服务挂了 zookeeper 服务器状态_初始化_02

上图的过程可以分为预启动初始化过程:

预启动

  1. 统一由 QuorumPeerMain 作为启动类。无论单机或集群,在 zkServer.cmd 和 zkServer.sh 中都配置了 QuorumPeerMain 作为启动入口类。
  2. 解析配置文件 zoo.cfg。zoo.cfg 配置运行时的基本参数,如 tickTime、dataDir、clientPort 等参数。
  3. 创建并启动历史文件清理器 DatadirCleanupManager 。对事务日志和快照数据文件进行定时清理。
  4. 判断当前是集群模式还是单机模式启动。若是单机模式,则委托给 ZookeeperServerMain 进行启动。
  5. 再次进行配置文件zoo.cfg的解析。
  6. 创建服务器实例 ZookeeperServer。Zookeeper 服务器首先会进行服务器实例的创建,然后对该服务器实例进行初始化,包括连接器、内存数据库、请求处理器等组件的初始化。

初始化

  1. 创建服务器统计器 ServerStats。ServerStats 是 Zookeeper 服务器运行时的统计器。
  2. 创建 Zookeeper 数据管理器 FileTxnSnapLog。FileTxnSnapLog 是 zookeeper 上层服务器和底层数据之间的对接层,提供了一系列操作数据文件的接口,如事务文件和快照数据文件。Zookeeper 根据 zoo.cfg 文件解析出来的快照数据目录 dataDir 和事务日志目录 dataLogDir 来创建 FileTxnSnapLog。
  3. 设置服务器 tickTime 和会话超时时间限制。
  4. 创建 ServerCnxnFactory 。通过配置系统属性 zookeeper.serverCnxnFactory 来指定使用 zookeeper 自己实现的 NIO 还是使用 Netty 框架作为 zookeeper服务端网络连接工厂。
  5. 初始化 ServerCnxnFactory。zookeeper会初始化 Thread 作为 ServerCnxnFactory 的主线程,然后再初始化 NIO 服务器。
  6. 启动 ServerCnxnFactory 主线程,进入Thread 的 run 方法,此时服务器还不能处理客户端请求。
  7. 恢复本地数据。启动时,需要从本地快照数据文件和事务日志进行数据恢复。
  8. 创建并启动会话管理器。zookeeper 会创建会话管理器 SessionTracker 进行会话管理。
  9. 初始化 zookeeper 的请求处理链。zookeeper 处理请求方式为责任链模式的实现,会有多个请求处理器依次处理一个客户端请求,在服务器启动时,会将这些请求处理器串联成一个请求处理链。
  10. 注册 JMX 服务。zookeeper 会将服务器运行时的一些信息以 JMX 的方式暴露给外部。
  11. 注册 zookeeper 服务实例。将 zookeeper 服务器实例注册给 ServerCnxnFactory ,之后 zookeeper就可以对外提供服务 。

集群服务器启动过程

单机和集群服务器的启动在很多地方是一致的,其流程图如下:

zookeeper注册服务挂了 zookeeper 服务器状态_服务器_03

上图的过程可以分为预启动、初始化、Leader 选举、Leader和Follower启动期交互、Leader与Follower启动 等过程。

预启动

  1. 统⼀由QuorumPeerMain作为启动类。
  2. 解析配置⽂件zoo.cfg。
  3. 创建并启动历史文件清理器 DatadirCleanupFactory。
  4. 判断当前是集群模式还是单机模式的启动。在集群模式中,在zoo.cfg⽂件中配置了多个服务器地址,可以选择集群启动。

初始化

  1. 创建ServerCnxnFactory。
  2. 初始化ServerCnxnFactory。
  3. 创建Zookeeper数据管理器FileTxnSnapLog。
  4. 创建QuorumPeer实例。Quorum是集群模式下特有的对象,是Zookeeper服务器实例(ZooKeeperServer)的托管者,QuorumPeer代表了集群中的⼀台机器,在运行期间, QuorumPeer会不断检测当前服务器实例的运行状态,同时根据情况发起Leader选举。
  5. 创建内存数据库ZKDatabase。ZKDatabase负责管理ZooKeeper的所有会话记录以及 DataTree和事务日志的存储。
  6. 初始化QuorumPeer。将核心组件如FileTxnSnapLog、ServerCnxnFactory、ZKDatabase 注册到QuorumPeer中,同时配置QuorumPeer的参数,如服务器列表地址、Leader选举算法和会话超时时间限制等。
  7. 恢复本地数据。
  8. 启动ServerCnxnFactory主线程。

Leader 选举

  1. 初始化 Leader 选举。
    集群模式特有,zookeeper 首先会根据自身的服务器 ID (SID)、最新的事务ID(ZXID)和当前服务器epoch(currentEpoch)来生成一个初始化投票,在初始化过程中,每个服务器都会给自己投票。然后根据zoo.cfg 的配置,创建指定的 Leader 选举算法实现,zookeeper 提供了三种算法(LeaderElection、AuthFastLeaderElection、FastLeaderElection),可以通过 zoo.cfg 中的 electionAlg 属性来指定,但目前只支持 FastLeaderElection 选举算法。
    在初始化阶段,zookeeper 会创建 Leader 选举所需的网络 I/O 层 QuorunCnxManager,同时启动对 Leader 选举端口的监听,等待集群中其他服务器创建连接。
  2. 注册 JMX 服务。
  3. 检测当前服务器状态
    运行期间,QuorumPeer 会不断检测当前服务器状态。在正常情况下,zookeeper 服务器的状态在 LOOKING/LEADING/FOLLOWING/OBSERVING 之间进行切换。在启动阶段,QuorumPeer 的初始状态是 LOOKING,因此开始进行 Leader 选举。
  4. Leader 选举
    zookeeper 的选举过程,简单地讲,就是一个集群中所有的机器互相之间进行一系列投票,选举产生最合适的机器成为 Leader ,同时其余机器成为 Follower 或是 Observer 的集群机器角色初始化过程。
    关于Leader 选举算法,简而言之,就是集群汇总哪个机器处理的数据越新(通常根据每个服务器处理过的最大 ZXID 来比较确定),越有可能成为 Leader ,其余机器称为 Follower 和 Observer。

Leader 和 Follower 启动期交互过程

到这里为止,zookeeper 已经完成了 Leader 选举,并且集群中每个服务器都已经确定了自己的角色。下面我们来对 Leader 和 Follower 在启动期间的交互进行介绍,其大致交互流程如图所示:

zookeeper注册服务挂了 zookeeper 服务器状态_初始化_04

  1. 创建 Leader 服务器和 Follower 服务器
    完成 Leader 选举后,每个服务器会根据自己服务器的角色创建相应的服务器实例,并进入各自角色的主流程
  2. Leader 服务器启动Follower接收器 LearnerCnxAcceptor
    运行期间,leader 服务器需要和所有的服务器(统称为 Leader)保持连接以确认集群机器的存活情况,LearnCnxAcceptor 负责接收所有非 Leader 服务器的连接请求
  3. Learner 服务器开始和 Leader 建立连接
    所有 Learner 会找到 Leader 服务器,并与其建立连接
  4. Leader 服务器创建 LearnerHandler
    Leader 接收到来自其他机器的连接创建请求后,会创建一个 LearnHandler 实例,每个 LearnerHandler 实例都对应一个 Leader 与 Learner 服务器之间的连接,负责Leader和 Learner 之间几乎所有的消息通信和数据同步
  5. 向 Leader 注册
    Learner 完成与 Leader 的连接后,会向 Leader 进行注册,即将 Learner 服务器的基本信息 (LearnerInfo),包括 SID 和 ZXID 发送给 Leader 服务器
  6. Leader 解析 Learner 信息,计算新的 epoch
    Leader 接收到 Learner 服务器基本信息后,会解析出 Learner 的 SID 和 ZXID ,然后根据 ZXID 解析出对应的 epoch_of_learner ,并和当前的 Leader 服务器的 epoch_of_leader 进行比较,如果 Learner 的值比较大,则更新Leader 的 epoch_of_leader = epoch_of_learner + 1 。然后LearnHandler 进行等待,知道过半 Learner 已经向Leader 进行了注册,同时更新了 epoch_of_leader 后,Leader 就可以确定当前集群的 epoch了。
  7. 发送 Leader 状态
    计算出新的 epoch 后,Leader 会将该选项以一个 LEADERINFO 消息形式发送给 Leader ,并等待 leader 的响应。
  8. Learner 发送ACK消息
    Learner 接收到 LEADERINFO 后,会解析出 epoch 和 ZXID ,然后向 Leader 反馈一个 ACKEPOCH 响应。
  9. 数据同步
    Leader 收到 Learner 的 ACKEPOCH 后,即可进行数据同步。
  10. 启动Leader和Learner服务器
    当有过半 Learner 已经完成了数据同步,那么 Leader 和 Learner 服务器实例就可以启动了。

Leader 和 Follower 启动

  1. 创建启动会话管理器
  2. 初始化zookeeper请求处理链,集群模式的每个处理器也会在启动阶段串联请求处理链。
  3. 注册 JMX 服务。

至此,zookeeper集群启动完毕。