本文對單機模式下,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