HBase源码分析3—HMaster启动过程
Main Entry
首先找一下启动的入口。从HBase的启动脚本中可以找到类似
|
1 2 |
if [ "$COMMAND" = "master" ] ; then CLASS='org.apache.hadoop.hbase.master.HMaster' |
从这里确定了入口的包 org.apache.hadoop.hbase.master ,在 HMaster 类中有 main 方法
|
1 2 3 4 |
public static void main(String[] args) { VersionInfo.logVersion(); new HMasterCommandLine(HMaster.class).doMain(args); } |
HMasterCommandLine 继承自 ServerCommandLine ,doMain()执行的是基类的方法,借助 ToolRunner 执行了 HMasterCommandLine.run() 。
|
1 2 3 4 5 6 7 8 9 10 11 |
public void doMain(String args[]) { try { int ret = ToolRunner.run(HBaseConfiguration.create(), this, args); if (ret != 0) { System.exit(ret); } } catch (Exception e) { LOG.error("Failed to run", e); System.exit(-1); } } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static int run(Configuration conf, Tool tool, String[] args) throws Exception{ if(conf == null) { conf = new Configuration(); } GenericOptionsParser parser = new GenericOptionsParser(conf, args); //set the configuration back, so that Tool can configure itself tool.setConf(conf); //get the args w/o generic hadoop args String[] toolArgs = parser.getRemainingArgs(); return tool.run(toolArgs); //这里,tool是doMain中传来的this,也就是HMasterCommandLine对象 } |
看下 HMasterCommandLine 做了什么。run方法做了一些参数检查的工作,最后调用了 startMaster()。
startMaster() 里分为两种模式,一种为’local’模式(即默认的standalone模式),在这种模式下会在本机JVM中同时启动master、Region server和Zookeeper,并在最后通过 LocalHBaseCluster 类对所有master、region server等创建现成和提供访问接口。
另一种模式就是distributed模式,就只会构造一个HMaster对象并调用 master.start()。
(注: HMaster.constructMaster 返回的实际上是HMaster的构造函数,start的是构造函数)
HMaster
init & wait
HMaster 继承自 HRegionServer,也有Region Server的功能,但是只存储关键的几个表。观察下HMaster.java,前400行基本都是定义了一些管理类,后面有空再慢慢分析这些类分别都是干啥的,先跳过。
HMaster的启动为两个部分,一部分是初始化 HRegionServer和启动 ActiveMasterManager ,这部分在HMaster的构造函数中完成,之后就会进入睡眠状态,等待被zk召唤成为primary master的那天,开始执行第二部分,执行 finishActiveMasterInitialization完成所有成员的初始化以及信息收集、节点管理等,正式接管master工作。
我们先看第一部分, HMaster 的构造函数,初始化了一堆配置然后启动了ActiveMasterManager
|
1 2 3 |
activeMasterManager = new ActiveMasterManager(zooKeeper, this.serverName, this); int infoPort = putUpJettyServer(); startActiveMasterManager(infoPort); |
ActiveMasterManager 这个对象是用于处理master选举过程的,负责与ZK进行通信,一旦确认成为primary master,会执行 finishActiveMasterInitialization 完成master启动流程。
跟一下 startActiveMasterManager 这个方法,内部先在ZK注册了一下自己为backup master身份,然后启动了一个线程,会hang在这里,等待召唤
|
1 2 3 |
if (activeMasterManager.blockUntilBecomingActiveMaster(timeout, status)) { finishActiveMasterInitialization(status); } |
blockUntilBecomingActiveMaster 里面是一个while循环,不断尝试注册成为主节点,一但成功就退出。
下面我们看看第二部分,当HMaster在ZK注册为primary master后做了什么事。
首先启动了一个监视器 zombieDetector , InitializationMonitor 对象监控master是否在配置的规定时间内初始化完毕,否则认为master启动失败,将会主动退出。
接下来初始化了若干必须的服务,如 fileSystemManager 、 tableLockManager 等,还有若干tracker,他们具体的内容后面我们慢慢研究。
接下来,新的master已选出,整个集群中的region server需要来注册:
|
1 2 3 4 5 6 7 8 9 10 |
// Wait for region servers to report in this.serverManager.waitForRegionServers(status); // Check zk for region servers that are up but didn't register for (ServerName sn : this.regionServerTracker.getOnlineServers()) { // The isServerOnline check is opportunistic, correctness is handled inside if (!this.serverManager.isServerOnline(sn) && serverManager.checkAndRecordNewServer(sn, ServerLoad.EMPTY_SERVERLOAD)) { LOG.info("Registered server found up in zk but who has not yet reported in: " + sn); } } |
waitForRegionServers返回有三个条件(需同时满足):
- 自上一个region server注册后一个周期时间内没有新的region server注册
- 总时间超时
- 注册数量达到配置的最少节点数
如果没有满足,则会一直等待region server过来注册。(极端情况如果hang死这这个地方,会被 InitializationMonitor 干掉,前提是设置了master启动的timeout)
显然这样不能保证所有的region server都过来注册过了,所以还得检查下是谁没来注册,打个log。
Log Splitting
接下来进行的任务是log splitting,因为HBase使用WAL机制,所以当机器宕机的时候内存中未落盘的数据会丢失,但是在WAL日志中可以找到记录做replay。由于每个region server管理多个region,把某个丢数据的region的日志从WAL日志中分离出来的过程就叫log splitting。
为了让master尽快启动,在master初始化阶段只进行hbase:mata的log splitting,
|
1 2 3 4 5 6 7 8 9 |
Set<ServerName> previouslyFailedServers = this.fileSystemManager.getFailedServersFromLogFolders(); |