在上一篇,我們了解了zookeeper最基本的配置,也從中了解一些配置的作用,那么這篇文章中,我們將介紹Zookeeper的啟動過程,我們在了解啟動過程的時候還要回過頭看看上一篇中各個配置參數在啟動時的位置。
Zookeeper的啟動入口在org.apache.zookeeper.server.quorum.QuorumPeerMain。
在這個類的main方法里進入了zookeeper的啟動過程,首先我們會解析配置文件,即zoo.cfg和myid。
這樣我們就知道了dataDir和dataLogDir指向哪兒了,然后就可以啟動日志清理任務了(如果配置了的話)。
DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config .getDataDir(), config.getDataLogDir(), config .getSnapRetainCount(), config.getPurgeInterval()); purgeMgr.start();
接下來會初始化ServerCnxnFactory,這個是用來接收來自客戶端的連接的,也就是這里啟動的是一個tcp server。在Zookeeper里提供兩種tcp server的實現,一個是使用java原生NIO的方式,另外一個是使用Netty。默認是java nio的方式,一個典型的Reactor模型。因為java nio編程並不是本文的重點,所以在這里就只是簡單的介紹一下。
//首先根據配置創建對應factory的實例:NIOServerCnxnFactory 或者 NettyServerCnxnFactory
ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();
//初始化配置 cnxnFactory.configure(config.getClientPortAddress(),config.getMaxClientCnxns());
創建幾個SelectorThread處理具體的數據讀取和寫出。
先是創建ServerSocketChannel,bind等
this.ss = ServerSocketChannel.open(); ss.socket().setReuseAddress(true); ss.socket().bind(addr); ss.configureBlocking(false);
然后創建一個AcceptThread線程來接收客戶端的連接。
這一部分就是處理客戶端請求的模塊了,如果遇到有客戶端請求的問題可以看看這部分。
接下來就進入初始化的主要部分了,首先會創建一個QuorumPeer實例,這個類就是表示zookeeper集群中的一個節點。初始化QuorumPeer的時候有這么幾個關鍵點:
1. 初始化FileTxnSnapLog,這個類主要管理Zookeeper中的操作日志(WAL)和snapshot。
2. 初始化ZKDatabase,這個類就是Zookeeper的目錄結構在內存中的表示,所有的操作最后都會映射到這個類上面來。
3. 初始化決議validator(QuorumVerifier->QuorumMaj) (其實這一步,是在配置)。這一步是從zoo.cfg的server.n這一部分初始化出集群的成員出來,有哪些需要參與投票(follower),有哪些只是observer。還有決定half是多少等,這些都是zookeeper的核心。在這一步,對於每個節點會初始化一個QuorumServer對象,並且放到allMembers,votingMembers,observingMembers這幾個map里。而且這里也對參與者的個數進行了一些判斷。
4. leader選舉 這一步非常重要,也是zookeeper里最復雜而最精華的一部分。
到這里,我們的zookeeper就啟動完成了。后面我將會分三部分進一步深入理解zookeeper:
1. leader選舉
2. 存儲
3. 處理客戶端請求