本文对单机模式下,ZooKeeper服务端的启动过程进行介绍
相关的类
- QuorumPeerMain:服务端启动的入口类
- DatadirCleanupManager:历史文件清理器
- ZooKeeperServerMain:单机模式下的启动类
QuorumPeerMain类的main方法,如下:
public static void main(String[] args) {
QuorumPeerMain main = new QuorumPeerMain();
try {
main.initializeAndRun(args);
}catch(){
//TODO
}
}
在initializeAndRun(args)方法中进行一系列的初始化工作
protected void initializeAndRun(String[] args) throws ConfigException, IOException, AdminServerException
{
QuorumPeerConfig config = new QuorumPeerConfig();
if (args.length == 1) {
config.parse(args[0]);
}
// 定时,启动历史文件的清理器
DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config
.getDataDir(), config.getDataLogDir(), config
.getSnapRetainCount(), config.getPurgeInterval());
purgeMgr.start();
// 对启动方式进行判断,集群模式还是单机模式
if (args.length == 1 && config.isDistributed()) {
//集群模式的启动入口
runFromConfig(config);
} else {
//单机模式的启动方式
ZooKeeperServerMain.main(args);
}
}
- 启动QuorumPeerMain类,执行main方法
- 解析配置文件,加载配置参数
- 启动定时的历史文件清理器DatadirCleanupManager
- 启动ZooKeeperServerMain类,执行其main方法
到这一步,ZooKeeper服务端的启动任务已经转移到了ZooKeeperServerMain中,下面我们就看看在main方法中都进行了哪些操作。
public static void main(String[] args) {
ZooKeeperServerMain main = new ZooKeeperServerMain();
try {
main.initializeAndRun(args);
}catch(){
//TODO
}
}
在initializeAndRun(args)完成的工作如下所示:
//注册log4j JMX mbeans
ManagedUtil.registerLog4jMBeans();
//从配置文件中启动服务端
runFromConfig(config);
在服务端的启动过程,涉及到的类有:
- FileTxnSnapLog:这是ZooKeeper上层服务器和底层数据存储之间的一个对接层,提供了一系列操作数据文件的接口,这些数据文件包括事务日志文件和快照数据文件,入参为数据快照目录dataDir和事务日志目录dataLogDir
- ServerStats:这是一个服务端的统计器,统计服务器运行的状态信息,关于这个类将在后面进行介绍
- ZooKeeperServerShutdownHandler:当服务器shutdown之后的处理类,有一个CountDownLatch的同步器控制
- ServerCnxnFactory
- ZooKeeperServer
- ContainerManager
ZooKeeperServerMain类中的runFromConfig(ServerConfig config)执行逻辑
主要代码如下:
public void runFromConfig(ServerConfig config) throws IOException, AdminServerException {
//实例化一个ZooKeeper服务端的数据管理器,提供一些接口操作事务日志文件、快照数据文件
FileTxnSnapLog txnLog = null;
//dataLogDir和dataDir是配置文件中的事务日志文件、数据快照文件的目录
txnLog = new FileTxnSnapLog(config.dataLogDir, config.dataDir);
//实例化一个ZooKeeperServer对象
final ZooKeeperServer zkServer = new ZooKeeperServer(txnLog,config.tickTime, config.minSessionTimeout, config.maxSessionTimeout, null);
//设置ServerStats
txnLog.setServerStats(zkServer.serverStats());
//向ZooKeeperServer对象注册一个ZooKeeperServerShutdownHandler
final CountDownLatch shutdownLatch = new CountDownLatch(1);
zkServer.registerServerShutdownHandler(new ZooKeeperServerShutdownHandler(shutdownLatch));
//得到一个ServerCnxnFactory对象,反射机制,具体看createFactory()方法
cnxnFactory = ServerCnxnFactory.createFactory();
//启动cnxnFactory, 在startup()中,进行主要的逻辑
cnxnFactory.startup(zkServer);
}
cnxnFactory.startup(zkServer)是服务端启动的主要逻辑所在,该方法采用的是模板模式。代码如下:
public void startup(ZooKeeperServer zkServer) throws IOException, InterruptedException {
startup(zkServer, true);
}
其真正的处理逻辑是由startup(zkServer, true)负责完成的。实现类NIOServerCnxnFactory中的代码如下:
@Override
public void startup(ZooKeeperServer zks, boolean startServer)
throws IOException, InterruptedException {
//启动服务端的一些线程,后面在慢慢研究
start();
//设置ZooKeeperServer对应的ServerCnxnFactory
setZooKeeperServer(zks);
if (startServer) {
//从FileTxnSnapLog中初始化数据
zks.startdata();
//启动ZooKeeperServer,完成诸如
//创建并启动会话管理器SessionTracker
//初始化ZooKeeper的请求处理链路
//注册JMX服务
//将ZooKeeperServer服务端的状态设置位running
//通知所有阻塞在这里的线程
zks.startup();
}
}
所以,在ZooKeeperServerMain这个类中,主要完成一系列初始化的配置+ServerCnxnFactory的runFromConfig。
具体的执行逻辑
- 初始化一个ZooKeeper服务端的数据管理器FileTxnSnapLog,作为事务日志文件和快照数据文件的管理器
- 解析配置参数,并根据FileTxnSnapLog对象来实例化一个ZooKeeperServer对象
- 为ZooKeeperServer注册一个ZooKeeperServerShutdownHandler
- 通过反射机制,得到一个ServerCnxnFactory对象
- 调用ServerCnxnFactory对象的startup()方法。该方法的具体执行逻辑见上文中方法的代码。
ServerCnxnFactory对象的startup()方法的执行逻辑 :
主要完成线程的初始化,以及ZooKeeperServer对象的一些初始化工作,流程如下:
- 调用ServerCnxnFactory的start方法,完成服务端网络连接的一些线程的问题(具体后文详细介绍,请持续关注)
- ZooKeeper服务端的数据文件的恢复
- 初始化并启动会话管理器,SessionTracker
- 初始化ZooKeeper服务端的请求处理链,典型的责任链模式
- PrepRequestProcessor
- SyncRequestProcessor
- FinalRequestProcessor
- 注册JMX服务
- 设置状态为running,然后notifyAll