HMaster 启动类org.apache.hadoop.hbase.master.HMaster
,HMaster 继承了 HRegionServer,实现了 MasterServices。
类描述:HMaster 可以运行多个,通过 Zookeeper 选出一个 Active Master,其他 HMaster 会阻塞在构造方法中,直到集群 shutdown 或 active master 丢失(
An HBase cluster has one active master. If many masters are started, all compete. Whichever wins goes on to run the cluster. All others park themselves in their constructor until master or cluster shutdown or until the active master loses its lease in zookeeper
)
0. HMaster 初始化
a. 初始化以下信息:
fatal error 缓存、Replication 信息、 压缩和加密信息(HBASE-6370)、HMaster 指标监控、表描述符(默认预加载)
b. 服务状态的推送(默认不开启),hbase.status.publisher.class
指定发布实现类
c. 启动内嵌的 JettyServer,默认监听"0.0.0.0:16010"端口,可以通过 web 的方式访问 master 的信息
d. 启动 ActiveMasterManager,连接ZK进行 Master 选举,如果不是 Master 的话,就一直阻塞。
public HMaster(final Configuration conf, CoordinatedStateManager csm)
throws IOException, KeeperException, InterruptedException {
super(conf, csm);
// 存放来自 region server 的 fatal error 信息,超过 buffer 大小后会自动清理。
this.rsFatals = new MemoryBoundedLogMessageBuffer(
conf.getLong("hbase.master.buffer.for.rs.fatals", 1*1024*1024));
// Disable usage of meta replicas in the master
this.conf.setBoolean(HConstants.USE_META_REPLICAS, false);
// 初始化 Replication 信息
Replication.decorateMasterConfiguration(this.conf);
// 初始化 HMaster 的压缩和加密信息
this.masterCheckCompression = conf.getBoolean("hbase.master.check.compression", true);
this.masterCheckEncryption = conf.getBoolean("hbase.master.check.encryption", true);
// Metrics for HMaster
this.metricsMaster = new MetricsMaster(new MetricsMasterWrapperImpl(this));
// 预加载表 Schema
this.preLoadTableDescriptors = conf.getBoolean("hbase.master.preload.tabledescriptors", true);
// ..
// ZK监控
activeMasterManager = new ActiveMasterManager(zooKeeper, this.serverName, this);
// 启动内嵌的 JettyServer,默认监听"0.0.0.0:16010"端口,可以通过 web 的方式访问 HMaster 的信息
int infoPort = putUpJettyServer();
// 选举 Master
startActiveMasterManager(infoPort);
}
1. 选举成为 Master 后会调用finishActiveMasterInitialization
创建监控HMaster线程(InitializationMonitor
),初始化以下对象或操作:
private void finishActiveMasterInitialization(MonitoredTask status)
throws IOException, InterruptedException, KeeperException, CoordinatedStateException {
isActiveMaster = true;
// 监控线程
Thread zombieDetector = new Thread(new InitializationMonitor(this));
zombieDetector.start();
// 包装 HDFS 操作
this.fileSystemManager = new MasterFileSystem(this, this);
// 设置 Meta 表的 Replication
this.tableDescriptors.get(TableName.META_TABLE_NAME)
.setRegionReplication(
conf.getInt(HConstants.META_REPLICAS_NUM, HConstants.DEFAULT_META_REPLICA_NUM));
// 加载表 Schema 信息,从 HDFS 上读取
if (preLoadTableDescriptors) {
this.tableDescriptors.getAll();
}
// 创建 ServerManager,管理 Region Server
this.serverManager = createServerManager(this, this);
// 提供访问集群里所有 Server 的方式
setupClusterConnection();
// 清楚表级别的 Write lock
this.tableLockManager.reapWriteLocks();
// 初始化一系列监控ZK的对象,详细见下文
initializeZKBasedSystemTrackers();
// 在处理请求前,初始化 master side coprocessors
// 提供Coprocessor的运行环境
this.cpHost = new MasterCoprocessorHost(this, this.conf);
// 启动 HMaster 处理任务的线程池
// MASTER_CLOSE_REGION hbase.master.executor.openregion.threads
// MASTER_OPEN_REGION hbase.master.executor.closeregion.threads
// MASTER_SERVER_OPERATIONS hbase.master.executor.serverops.threads
// MASTER_META_SERVER_OPERATIONS hbase.master.executor.serverops.threads
// M_LOG_REPLAY_OPS hbase.master.executor.logreplayops.threads
// MASTER_TABLE_OPERATIONS 1
startServiceThreads();
// 等待 RegionServer 的汇报
// 1. 向 HMaster 汇报的 RegionServer 数量达到hbase.master.wait.on.regionservers.maxtostart(Integer.MAX_VALUE)
// 2. 向 HMaster 汇报的 RegionRerver 数量达到hbase.master.wait.on.regionservers.mintostart(1),
// 并且等待时间超过hbase.master.wait.on.regionservers.timeout(4500ms)
// 同时在hbase.master.wait.on.regionservers.interval(1500ms)内向 HMaster 注册的 RegionServer 数量没有变
// 在同时满足以上条件后结束等待
this.serverManager.waitForRegionServers(status);
// 检查在ZK当中注册了,但是没在 HMaster 这里注册的 RegionServer
for (ServerName sn: this.regionServerTracker.getOnlineServers()) {
// 只输出日志,不处理
}
// ... 分配Meta Region
}
1.1 initializeZKBasedSystemTrackers
创建以下对象:
// RegionServer region balancer,控制 RegionServer 负载
// 返回 RegionPlan(Region 应该放在哪个 RegionServer 上)
// 默认为 StochasticLoadBalancer
this.balancer = LoadBalancerFactory.getLoadBalancer(conf);
// 用于 Region 的 split 和 merge 使得一个 table 的所有 region 的大小趋于均衡
// 默认为 SimpleRegionNormalizer
this.normalizer = RegionNormalizerFactory.getRegionNormalizer(conf);
// 监听 load balancer 状态
// ZK节点 /hbase/balancer(zookeeper.znode.balancer)
this.loadBalancerTracker = new LoadBalancerTracker(zooKeeper, this);
// 监听 region normalizer 状态
// ZK节点 /hbase/normalizer(zookeeper.znode.regionNormalizer)
this.regionNormalizerTracker = new RegionNormalizerTracker(zooKeeper, this);
// 负责 Assign Region,RPC通知 RegionServer 执行 open region 操作
// 这里能找到 RIT 的 Region
// 监听 /hbase/region-in-transition 节点(zookeeper.znode.unassigned)
this.assignmentManager = new AssignmentManager(this, serverManager,
this.balancer, this.service, this.metricsMaster,
this.tableLockManager);
// 监听 RegionServer 的状态
// ZK节点 /hbase/rs(zookeeper.znode.rs)
this.regionServerTracker = new RegionServerTracker(zooKeeper, this,
this.serverManager);
// 监听 RegionServer(下线的) 的状态
// ZK节点 /hbase/draining(zookeeper.znode.draining.rs)
this.drainingServerTracker = new DrainingServerTracker(zooKeeper, this,
this.serverManager);
// 监听 cluster 是否正常运行
// ZK节点 /hbase/running(zookeeper.znode.state)的内容为当前 HMaster 的信息
boolean wasUp = this.clusterStatusTracker.isClusterUp();
if (!wasUp) this.clusterStatusTracker.setClusterUp();
// 注册 SnapshotManager、MasterFlushTableProcedureManager 和其他ProcedureManager
// Procedure 负责处理对 Table 的创建、修改、Flush 等操作
// mpmHost 提供 Procedure 的运行环境
this.snapshotManager = new SnapshotManager();
this.mpmHost = new MasterProcedureManagerHost();
this.mpmHost.register(this.snapshotManager);
this.mpmHost.register(new MasterFlushTableProcedureManager());
this.mpmHost.loadProcedures(conf);
2. 在第一步操作完,初始化了各种对象后,需要分配 META 表
在此之前,恢复 Meta 表,对 failed server 上的 meta region 执行 split
private void finishActiveMasterInitialization(MonitoredTask status)
throws IOException, InterruptedException, KeeperException, CoordinatedStateException {
// ...
// 注释:在 Master 启动过程中会恢复 meta region server
// 其他失败的 rs 建议通过 SSH 处理会尽可能快速启动 Master
// 从 WALs 目录下找出之前失败或的RS
// HDFS 目录 /hbase/WALs 下每一个 RegionServer 有一个子目录,从 /hbase/WALs 中解析出所有的RS,不在 onlineServers 中的即认为是失败的。
Set<ServerName> previouslyFailedServers =
this.fileSystemManager.getFailedServersFromLogFolders();
// log splitting for hbase:meta server
// 获得 meta region 所在的 RegionServer
// ZK节点 /hbase/meta-region-server 存储之前 meta region 所在的 server
ServerName oldMetaServerLocation = metaTableLocator.getMetaRegionLocation(this.getZooKeeper());
// 如果之前 meta region 所在的 server 在 failed server 列表中,则认为 meta region 需要恢复
if (oldMetaServerLocation != null && previouslyFailedServers.contains(oldMetaServerLocation)) {
// 执行 split meta log
splitMetaLogBeforeAssignment(oldMetaServerLocation);
}
// ...
}
private void splitMetaLogBeforeAssignment(ServerName currentMetaServer)
throws IOException {
// hbase.master.distributed.log.replay 属性,默认是 false,即 log split
// RecoveryMode 是 LOG_REPLAY(日志重放),将 meta region 放到ZK的 /hbase/recovering-regions下
if (RecoveryMode.LOG_REPLAY == this.getMasterFileSystem().getLogRecoveryMode()) {
Set<HRegionInfo> regions = new HashSet<HRegionInfo>();
regions.add(HRegionInfo.FIRST_META_REGIONINFO);
this.fileSystemManager.prepareLogReplay(currentMetaServer, regions);
}
// RecoveryMode 是 LOG_SPLITTING(日志切分)的 meta region 所在的failed region server 的 WAL log 做 split log 操作
else {
this.fileSystemManager.splitMetaLog(currentMetaServer);
}
}
2.1 调用 splitLog 方法执行 split 日志的操作
public void splitLog(final Set<ServerName> serverNames, PathFilter filter)
throws IOException {
long splitTime = 0, splitLogSize = 0;
// 修改 WALs 日志目录的名称,在需要 split 的目录的名称后面加上.splitting
List<Path> logDirs = getLogDirs(serverNames);
// splitLogManager 记录 dead server 列表
splitLogManager.handleDeadWorkers(serverNames);
// 执行 split 日志
splitLogSize = splitLogManager.splitLogDistributed(serverNames, logDirs, filter);
// 记录 split 结果到 MetricsMaster 当中
// 使用 path filter 区分 META 表和普通表,META 表的日志以.meta结尾
if (this.metricsMasterFilesystem != null) {
if (filter == META_FILTER) {
this.metricsMasterFilesystem.addMetaWALSplit(splitTime, splitLogSize);
} else {
this.metricsMasterFilesystem.addSplit(splitTime, splitLogSize);
}
}
}
/**
* 执行 Split log
* 在所有指定 region server 的 META 表日志处理结束(成功或失败)前阻塞
* @param logDirs List of log dirs to split
* @param filter the Path filter to select specific files for considering
* @return cumulative size of the logfiles split
*/
public long splitLogDistributed(final Set<ServerName> serverNames, final List<Path> logDirs,
PathFilter filter) throws IOException {
FileStatus[] logfiles = getFileList(logDirs, filter);
// ...
// 统计任务完成结果
TaskBatch batch = new TaskBatch();
Boolean isMetaRecovery = (filter == null) ? null : false;
for (FileStatus lf : logfiles) {
String pathToLog = FSUtils.removeRootPath(lf.getPath(), conf);
// 把任务插入到 Split 任务列表当中
// 在ZK节点 /hbase/splitWAL下创建原来的相对路径名加密编码后的值
if (!enqueueSplitTask(pathToLog, batch)) {
throw new IOException("duplicate log split scheduled for " + lf.getPath());
}
}
// 等待任务结束
// RegionServer 会有 SplitLogWorker 读取ZK节点 /hbase/splitWAL 处理 Split
// 参考 SplitLogWorker.splitLogFile
waitForSplittingCompletion(batch, status);
// remove recovering regions
if (filter == MasterFileSystem.META_FILTER) {
isMetaRecovery = true;
}
// 清理 recovering 的状态
// region server 不让访问 recovering 状态的 region
removeRecoveringRegions(serverNames, isMetaRecovery);
if (batch.done != batch.installed) {
// 启动的任务和完成的任务不相等的情况
// ... 记录异常
throw new IOException(msg);
}
// 清理 Split 前的log文件
for (Path logDir : logDirs) {
final FileSystem fs = logDir.getFileSystem(conf);
try {
if (fs.exists(logDir) && !fs.delete(logDir, false)) {
LOG.warn("Unable to delete log src dir. Ignoring. " + logDir);
}
} catch (IOException ioe) {
// ...
}
}
return totalSize;
}
2.2 分配 Meta 表,调用assignMeta
void assignMeta(MonitoredTask status, Set<ServerName> previouslyFailedMetaRSs, int replicaId)
throws InterruptedException, IOException, KeeperException {
// Work on meta region
int assigned = 0;
RegionStates regionStates = assignmentManager.getRegionStates();
// 从ZK节点 /hbase/meta-region-server 获取当前 meta state
RegionState metaState = MetaTableLocator.getMetaRegionState(getZooKeeper(), replicaId);
// meta 表第一个 region
HRegionInfo hri = RegionReplicaUtil.getRegionInfoForReplica(HRegionInfo.FIRST_META_REGIONINFO,
replicaId);
ServerName currentMetaServer = metaState.getServerName();
// Add a region to RegionStates
if (!ConfigUtil.useZKForAssignment(conf)) {
regionStates.createRegionState(hri, metaState.getState(),
currentMetaServer, null);
} else {
regionStates.createRegionState(hri);
}
// If region is up in zk in transition, then do fixup and block and wait until
// the region is assigned and out of transition.
// 处理 meta 表第一个 region
boolean rit = this.assignmentManager.
processRegionInTransitionAndBlockUntilAssigned(hri);
// 在 timeout 时间内等待 hbase:meta 表是否可以被访问
boolean metaRegionLocation = metaTableLocator.verifyMetaRegionLocation(
this.getConnection(), this.getZooKeeper(), timeout, replicaId);
if (!metaRegionLocation || !metaState.isOpened()) {
// Meta location is not verified. It should be in transition, or offline.
// We will wait for it to be assigned in enableSSHandWaitForMeta below.
if (!ConfigUtil.useZKForAssignment(conf)) {
assignMetaZkLess(regionStates, metaState, timeout, previouslyFailedMetaRSs);
} else if (!rit) {
// 重新执行之前的 Split log 操作
if (currentMetaServer != null) {
if (serverManager.isServerOnline(currentMetaServer)) {
serverManager.expireServer(currentMetaServer);
}
if (replicaId == HRegionInfo.DEFAULT_REPLICA_ID) {
splitMetaLogBeforeAssignment(currentMetaServer);
previouslyFailedMetaRSs.add(currentMetaServer);
}
}
// 重新 assign 一次 meta 表
assignmentManager.assignMeta(hri);
}
}
else {
// assign 成功,更新状态为 online
regionStates.updateRegionState(
HRegionInfo.FIRST_META_REGIONINFO, State.OPEN, currentMetaServer);
this.assignmentManager.regionOnline(
HRegionInfo.FIRST_META_REGIONINFO, currentMetaServer);
}
// ZK中设置 meta 表启用状态
if (replicaId == HRegionInfo.DEFAULT_REPLICA_ID) enableMeta(TableName.META_TABLE_NAME);
// ...
}
在 AssignmentManager 中调用assign
,向 RegionServer 发请求 open region
regionOpenState = serverManager.sendRegionOpen(
plan.getDestination(), region, versionOfOfflineNode, favoredNodes);
3. 恢复其他 region
回到finishActiveMasterInitialization
方法中,对 dead server 进行处理
// previouslyFailedServers 是之前判断出来的 dead server
for (ServerName tmpServer : previouslyFailedServers) {
// 将这些 server 保存起来,master 不会等待他们都恢复完再继续
this.serverManager.processDeadServer(tmpServer, true);
}
恢复这些 region 的过程比较慢,涉及到 WAL log split 和 region assign,HMaster 不会等待他们恢复
分配 region 的工作都是由 assignmentManager 来完成的,调用assignmentManager.joinCluster()
// 如果是新启动的,就分配所有的用户 region
// 如果是 failover 的情况,就修复 assignmentManager 当中有问题的 region 状态,
void joinCluster() throws IOException,
KeeperException, InterruptedException, CoordinatedStateException {
long startTime = System.currentTimeMillis();
// 获得 dead server 列表
// Scan hbase:meta 表构建 region、server和 assignment 列表
// replicasToClose 保存需要重新 assign 的 region(merge 和 split 状态的region)
// offlineServers 保存 dead server(region 所在 server 不在 onlineServer)
Set<ServerName> deadServers = rebuildUserRegions();
// 处理 deadServer 和正在 merge 或 transition 没有完成的 region
// 在方法里要判断是否是 failover 的情况
boolean failover = processDeadServersAndRegionsInTransition(deadServers);
// 清除ZK节点 /hbase/region-in-transition(zookeeper.znode.unassigned)
if (!useZKForAssignment) {
ZKUtil.deleteNodeRecursively(watcher, watcher.assignmentZNode);
}
// 恢复在 Enabling 和 Disabling 状态的表
recoverTableInDisablingState();
recoverTableInEnablingState();
}
3.1 processDeadServersAndRegionsInTransition
方法
主要逻辑用于判断是否是 failover
// Process all regions that are in transition in zookeeper and also
// processes the list of dead servers.
boolean processDeadServersAndRegionsInTransition(final Set<ServerName> deadServers)
throws KeeperException, IOException, InterruptedException, CoordinatedStateException {
// 读ZK的节点 /hbase/region-in-transition 获取需要 assignment 的 region
List<String> nodes = ZKUtil.listChildrenNoWatch(watcher, watcher.assignmentZNode);
// serverManager 里有 deadServer
boolean failover = !serverManager.getDeadServers().isEmpty();
if (failover) {
// ...
} else {
// 如果除了 meta region 外有 region 是 assigned 状态,是 failover
Set<ServerName> onlineServers = serverManager.getOnlineServers().keySet();
for (Map.Entry<HRegionInfo, ServerName> en:
regionStates.getRegionAssignments().entrySet()) {
HRegionInfo hri = en.getKey();
if (!hri.isMetaTable()
&& onlineServers.contains(en.getValue())) {
failover = true;
break;
}
}
if (!failover && nodes != null) {
// 如果除了 meta region 外有 region 是 RIT 状态(有 split 或者 merge 还没有完成的 region)是 failover
for (String encodedName: nodes) {
RegionState regionState = regionStates.getRegionState(encodedName);
if (regionState != null && !regionState.getRegion().isMetaRegion()) {
failover = true;
break;
}
}
}
}
if (!failover && !useZKForAssignment) {
// 如果除了 meta region 外有 region 是 RIT 状态(有 split 或者 merge 还没有完成的 region)是 failover
Map<String, RegionState> regionsInTransition = regionStates.getRegionsInTransition();
if (!regionsInTransition.isEmpty()) {
Set<ServerName> onlineServers = serverManager.getOnlineServers().keySet();
for (RegionState regionState: regionsInTransition.values()) {
ServerName serverName = regionState.getServerName();
if (!regionState.getRegion().isMetaRegion()
&& serverName != null && onlineServers.contains(serverName)) {
failover = true;
break;
}
}
}
}
if (!failover) {
// 如果 dead server 的 WALs 路径下有 splitting log,是 failover
Set<ServerName> queuedDeadServers = serverManager.getRequeuedDeadServers().keySet();
if (!queuedDeadServers.isEmpty()) {
// ...
for (ServerName serverName: queuedDeadServers) {
// ...
Path splitDir = logDir.suffix(DefaultWALProvider.SPLITTING_EXT);
if (fs.exists(logDir) || fs.exists(splitDir)) {
failover = true;
break;
}
}
if (!failover) {
// 如果不是 failover,清除 dead server
serverManager.removeRequeuedDeadServers();
}
}
}
Set<TableName> disabledOrDisablingOrEnabling = null;
Map<HRegionInfo, ServerName> allRegions = null;
if (!failover) {
disabledOrDisablingOrEnabling = tableStateManager.getTablesInStates(
ZooKeeperProtos.Table.State.DISABLED,
ZooKeeperProtos.Table.State.DISABLING,
ZooKeeperProtos.Table.State.ENABLING);
// mark all user regions closed before reassignment
allRegions = regionStates.closeAllUserRegions(
disabledOrDisablingOrEnabling);
}
// Now region states are restored
regionStateStore.start();
if (failover) {
// 如果是 failover,处理 dead server 和 RIT
// dead server 通过 ServerCrashProcedure 异步完成
// region in transition 同步完成
// See HBASE-4580 for more information.
processDeadServersAndRecoverLostRegions(deadServers);
}
if (!failover && useZKForAssignment) {
// 清除ZK监听,并启动新的监听
ZKAssign.deleteAllNodes(watcher);
ZKUtil.listChildrenAndWatchForNewChildren(this.watcher,
this.watcher.assignmentZNode);
}
if (!failover) {
// assign 所有的 regions
assignAllUserRegions(allRegions);
}
// ...
}
3.2 异步 assign region
private void assign(int regions, int totalServers,
String message, Map<ServerName, List<HRegionInfo>> bulkPlan)
throws InterruptedException, IOException {
int servers = bulkPlan.size();
// hbase.bulk.assignment.threshold.regions
// hbase.bulk.assignment.threshold.servers
// 如果 region 数量或着 server 数量超过阈值,使用 bulk assign
if (servers == 1 || (regions < bulkAssignThresholdRegions
&& servers < bulkAssignThresholdServers)) {
// 小集群下效率更高
ArrayList<HRegionInfo> userRegionSet = new ArrayList<HRegionInfo>(regions);
for (Map.Entry<ServerName, List<HRegionInfo>> plan: bulkPlan.entrySet()) {
if (!assign(plan.getKey(), plan.getValue())) {
for (HRegionInfo region: plan.getValue()) {
if (!regionStates.isRegionOnline(region)) {
// 异步 assign
// 线程池中调用 assignmentManager.assign(hri, true, newPlan);
// 线程池大小 hbase.assignment.threads.max,默认30
invokeAssign(region);
}
}
}
}
// 等待 assignment 完成
// 等待时间 hbase.bulk.assignment.perregion.open.time * (reassigningRegions + 1)
if (!waitForAssignment(userRegionSet, true, userRegionSet.size(),
System.currentTimeMillis())) {
// ....
}
} else {
// bulk assign
// 使用 fixed 线程池 assign
BulkAssigner ba = new GeneralBulkAssigner(
this.server, bulkPlan, this, bulkAssignWaitTillAllAssigned);
ba.bulkAssign();
}
}
分配用户 region 的方法和分配 meta 的过程基本一致。
4. 开启一系列调度,由 choreService 执行
// master.getClusterStatus()
// 获取 clusterStatus,用于 loadBalancer 决定 assign region 到哪个 server 上
this.clusterStatusChore = new ClusterStatusChore(this, balancer);
getChoreService().scheduleChore(clusterStatusChore);
// master.balance()
// 获得 RegionPlan(需要移动的 region info,source region server 和 dest region server)
// 只负责根据 clusterStatus 生成 RegionPlan,region 的迁移则是由 assignmentManager 根据 plan 完成
this.balancerChore = new BalancerChore(this);
getChoreService().scheduleChore(balancerChore);
// master.normalizeRegions()
// 使得一个 table 的所有 region 的大小趋于均衡
// split 过大的 region,merge 太小的 region
// 生成 NormalizationPlan(SplitNormalizationPlan、MergeNormalizationPlan、EmptyNormalizationPlan)
// AdminService 会发送 RPC 到某个 region server 让其对 region split 或者 merge
this.normalizerChore = new RegionNormalizerChore(this);
getChoreService().scheduleChore(normalizerChore);
// 对于被 merge 或 split 操作成为新 region
// 定期 scan meta table,如果新 region 不在持有旧 region 的 reference file
// 可以移除旧 region(HFile 移动到 HDFS 目录 /hbase/archive/{tableName}/{encoded-region-name} 路径下)
this.catalogJanitorChore = new CatalogJanitor(this, this);
getChoreService().scheduleChore(catalogJanitorChore);
5. 其他操作
// 创建 TableNamespaceManager,创建、访问、操作 namespace 的包装类
initNamespace();
// 创建 MasterQuotaManager,创建、访问、操作 quota 的包装类
initQuotaManager();
// 清除与 online server 有相同 host name 和 port 的dead server
// See HBASE-5916.
this.serverManager.clearDeadServersWithSameHostNameAndPortOfOnlineServer();
// Check and set the znode ACLs if needed in case we are overtaking a non-secure configuration
zooKeeper.checkAndSetZNodeAcls();
...
HMaster的主要启动流程如上所诉。欢迎补充和提出错误。