Zookeeper啟動(dòng)源碼詳解
簡(jiǎn)介
啟動(dòng)源碼分析
Zookeeper啟動(dòng)的主類(lèi)為QuorumPeerMain.java 。入口函數文為initializeAndRun,如下所示,在往下的核心函數為runFromConfig。
QuorumPeerMain main = new QuorumPeerMain();
try {
main.initializeAndRun(args);
} catch (IllegalArgumentException e) {
// 啟動(dòng)異常處理。
}
LOG.info("Exiting normally");
ServiceUtils.requestSystemExit(ExitCode.EXECUTION_FINISHED.getValue());
runFromConfig函數里面主要做了下面幾件事:
- 初始化log4j相關(guān)的jmx。
- 初始化監控相關(guān)組件。
- 初始化認證相關(guān)組件。
- 設置基礎配置信息。
- 啟動(dòng)Zookeeper。由
quorumPeer.start();開(kāi)始。相關(guān)的類(lèi)為:QuorumPeer.java
public void runFromConfig(QuorumPeerConfig config) throws IOException, AdminServerException {
try {
// 注冊和log4j相關(guān)的jmx監控
ManagedUtil.registerLog4jMBeans();
} catch (JMException e) {
LOG.warn("Unable to register log4j JMX control", e);
}
LOG.info("Starting quorum peer, myid=" + config.getServerId());
final MetricsProvider metricsProvider;
try {
metricsProvider = MetricsProviderBootstrap.startMetricsProvider(
config.getMetricsProviderClassName(),
config.getMetricsProviderConfiguration());
} catch (MetricsProviderLifeCycleException error) {
throw new IOException("Cannot boot MetricsProvider " + config.getMetricsProviderClassName(), error);
}
try {
// 初始化監控相關(guān)
ServerMetrics.metricsProviderInitialized(metricsProvider);
// 初始化認證相關(guān)信息
ProviderRegistry.initialize();
// 省略部分
quorumPeer = getQuorumPeer();
// 設置基礎配置文件
quorumPeer.setTxnFactory(new FileTxnSnapLog(config.getDataLogDir(), config.getDataDir()));
quorumPeer.enableLocalSessions(config.areLocalSessionsEnabled());
quorumPeer.enableLocalSessionsUpgrading(config.isLocalSessionsUpgradingEnabled());
// 省略部分
// sets quorum sasl authentication configurations
quorumPeer.setQuorumSaslEnabled(config.quorumEnableSasl);
if (quorumPeer.isQuorumSaslAuthEnabled()) {
// 開(kāi)啟sasl之后,設置相關(guān)參數
quorumPeer.setQuorumServerSaslRequired(config.quorumServerRequireSasl);
quorumPeer.setQuorumLearnerSaslRequired(config.quorumLearnerRequireSasl);
quorumPeer.setQuorumServicePrincipal(config.quorumServicePrincipal);
quorumPeer.setQuorumServerLoginContext(config.quorumServerLoginContext);
quorumPeer.setQuorumLearnerLoginContext(config.quorumLearnerLoginContext);
}
quorumPeer.setQuorumCnxnThreadsSize(config.quorumCnxnThreadsSize);
quorumPeer.initialize();
if (config.jvmPauseMonitorToRun) {
quorumPeer.setJvmPauseMonitor(new JvmPauseMonitor(config));
}
// 開(kāi)始啟動(dòng)
quorumPeer.start();
ZKAuditProvider.addZKStartStopAuditLog();
quorumPeer.join();
} catch (InterruptedException e) {
// warn, but generally this is ok
LOG.warn("Quorum Peer interrupted", e);
} finally {
try {
metricsProvider.stop();
} catch (Throwable error) {
LOG.warn("Error while stopping metrics", error);
}
}
}
真正啟動(dòng)的函數為QuorumPeer的start函數。主要做了下面事:
-
加載數據,包括log文件里面和snapshot里面的數據,在數據量較大的情況下,當前步驟可能比較慢。
-
啟動(dòng)管理服務(wù),主要用于管理Zookeeper服務(wù)端。主要實(shí)現方式包含:
- JettyAdminServer:提供http方式的servier,通過(guò)CommandServlet實(shí)現管理接口,主要是四字命令。
- DummyAdminServer:實(shí)際上就是啥也沒(méi)有,不只是管理的意思。
-
開(kāi)始參與選舉Leader。
-
啟動(dòng)JVM 延時(shí)檢測線(xiàn)程。
public synchronized void start() {
if (!getView().containsKey(myid)) {
throw new RuntimeException("My id " + myid + " not in the peer list");
}
// 加載數據,當前步驟可能比較慢。
loadDataBase();
startServerCnxnFactory();
try {
adminServer.start();
} catch (AdminServerException e) {
LOG.warn("Problem starting AdminServer", e);
}
// 開(kāi)始Leader選舉
startLeaderElection();
startJvmPauseMonitor();
super.start();
}
zookeeper數據加載主要通過(guò)ZKDatabase.java實(shí)現。加載數據的入口函數為loadDataBase。核心還是FileTxnSnapLog.restore函數。
public long loadDataBase() throws IOException {
long startTime = Time.currentElapsedTime();
// 加載snapshot文件和log文件
long zxid = snapLog.restore(dataTree, sessionsWithTimeouts, commitProposalPlaybackListener);
initialized = true;
long loadTime = Time.currentElapsedTime() - startTime;
ServerMetrics.getMetrics().DB_INIT_TIME.add(loadTime);
LOG.info("Snapshot loaded in {} ms, highest zxid is 0x{}, digest is {}",
loadTime, Long.toHexString(zxid), dataTree.getTreeDigest());
return zxid;
}
評論
0 評論