简介
启动源码分析
Zookeeper 启动的主类为 QuorumPeerMain.java 。入口函数文为 initializeAndRun,如下所示,在往下的核心函数为 runFromConfig。
QuorumPeerMain main = new QuorumPeerMain();
try {
main.initializeAndRun(args);
} catch (IllegalArgumentException e) {
// 启动异常处理。
}
LOG.info("Exiting normally");
ServiceUtils.requestSystemExit(ExitCode.EXECUTION_FINISHED.getValue());
runFromConfig 函数里面主要做了下面几件事:
- 初始化 log4j 相关的 jmx。
- 初始化监控相关组件。
- 初始化认证相关组件。
- 设置基础配置信息。
- 启动 Zookeeper。由
quorumPeer.start();
开始。相关的类为:QuorumPeer.java
public void runFromConfig(QuorumPeerConfig config) throws IOException, AdminServerException {
try {
// 注册和log4j相关的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 {
// 初始化监控相关
ServerMetrics.metricsProviderInitialized(metricsProvider);
// 初始化认证相关信息
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()) {
// 开启sasl之后,设置相关参数
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));
}
// 开始启动
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);
}
}
}
真正启动的函数为 QuorumPeer 的 start 函数。主要做了下面事:
-
加载数据,包括 log 文件里面和 snapshot 里面的数据,在数据量较大的情况下,当前步骤可能比较慢。
-
启动管理服务,主要用于管理 Zookeeper 服务端。主要实现方式包含:
- JettyAdminServer:提供 http 方式的 servier,通过 CommandServlet 实现管理接口,主要是四字命令。
- DummyAdminServer:实际上就是啥也没有,不只是管理的意思。
-
开始参与选举 Leader。
-
启动 JVM 延时检测线程。
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);
}
// 开始Leader选举
startLeaderElection();
startJvmPauseMonitor();
super.start();
}
zookeeper 数据加载主要通过 ZKDatabase.java 实现。加载数据的入口函数为 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;
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于