第二篇 hbase2.4.2 源码分析 RegionServer启动流程
前言
1.看什么? 看HRegionServer类说明 看main()入口 看初始化了哪些重要组件 如何进行远程调用 如何看:看过程中画图,或者把方法的调用关系,对象的调用按照调用关系记录下来,本文按照第二种方式进行编写一、HRegionServer类继承关系
看什么?
看类说明,看继承关系
从哲学角度看:这是性质问题
HRegionServer 是个线程,实现 RegionServerServices, LastSequenceId, ConfigurationObserver 几个接口,既然是线程,肯定有run方法
/**
* HRegionServer makes a set of HRegions available to clients. It checks in with
* the HMaster. There are many HRegionServers in a single HBase deployment.
*/
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
@SuppressWarnings({ "deprecation"})
public class HRegionServer extends Thread implements
RegionServerServices, LastSequenceId, ConfigurationObserver {
二、HRegionServer.main入口分析
1.main入口
/**
* @see org.apache.hadoop.hbase.regionserver.HRegionServerCommandLine
*/
public static void main(String[] args) {
LOG.info("STARTING executorService " + HRegionServer.class.getSimpleName());
VersionInfo.logVersion();
Configuration conf = HBaseConfiguration.create();
@SuppressWarnings("unchecked")
Class<? extends HRegionServer> regionServerClass = (Class<? extends HRegionServer>) conf
.getClass(HConstants.REGION_SERVER_IMPL, HRegionServer.class);
new HRegionServerCommandLine(regionServerClass).doMain(args);
}
HRegionServerCommandLine.doMain()如下
/**
* Parse and run the given command line. This may exit the JVM if
* a nonzero exit code is returned from <code>run()</code>.
*/
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);
}
}
public static int run(Configuration conf, Tool tool, String[] args) throws Exception {
if (CallerContext.getCurrent() == null) {
CallerContext ctx = (new Builder("CLI")).build();
CallerContext.setCurrent(ctx);
}
if (conf == null) {
conf = new Configuration();
}
GenericOptionsParser parser = new GenericOptionsParser(conf, args);
tool.setConf(conf);
String[] toolArgs = parser.getRemainingArgs();
//在这里真正调用,org.apache.hadoop.util.Tool竟然是Hadoop包的,我在想,为什么,不直接在hbase包下启动就好了,吐槽。。。
return tool.run(toolArgs);
}
tool就是: HRegionServerCommandLine, 找HRegionServerCommandLine.run()
@Override
public int run(String args[]) throws Exception {
if (args.length != 1) {
usage(null);
return 1;
}
String cmd = args[0];
if ("start".equals(cmd)) {
//启动代码,追进去看看
return start();
} else if ("stop".equals(cmd)) {
System.err.println(
"To shutdown the regionserver run " +
"hbase-daemon.sh stop regionserver or send a kill signal to " +
"the regionserver pid");
return 1;
} else {
usage("Unknown command: " + args[0]);
return 1;
}
}
//到达启动流程
private int start() throws Exception {
Configuration conf = getConf();
TraceUtil.initTracer(conf);
try {
// If 'local', don't start a region server here. Defer to
// LocalHBaseCluster. It manages 'local' clusters.
//local模式
if (LocalHBaseCluster.isLocal(conf)) {
LOG.warn("Not starting a distinct region server because "
+ HConstants.CLUSTER_DISTRIBUTED + " is false");
} else {
//集群模式
logProcessInfo(getConf());
HRegionServer hrs = HRegionServer.constructRegionServer(regionServerClass, conf);
hrs.start(); //启动,触发HRegionServer的run方法
hrs.join(); //等待线程结束
if (hrs.isAborted()) {
throw new RuntimeException("HRegionServer Aborted");
}
}
} catch (Throwable t) {
LOG.error("Region server exiting", t);
return 1;
}
return 0;
}
2.HRegionServer.run()分析 核心服务都在这启动
代码如下(示例):
run()
preRegistrationInitialization
setupClusterConnection()
初始化clusterConnection和MetaTableLocator
initializeZooKeeper()
initializeThreads()
跟master进行注册
RegionServerStartupResponse w = reportForDuty();
handleReportForDutyResponse()处理master返回的响应
createMyEphemeralNode() 在zk的/rs目录进行注册(创建临时节点)
initializeFileSystem();
setupWALAndReplication();
startReplicationService()
JvmPauseMonitor() jvm fullGC停顿检测线程
startServices() --启动很多服务和线程
HeapMemoryManager管理器启动
三、 HRegionServer和master的rpc如何调用?
RegionServerStartupResponse w = reportForDuty();
RegionServerStartupRequest.Builder request = RegionServerStartupRequest.newBuilder();
if (!StringUtils.isBlank(useThisHostnameInstead)) {
request.setUseThisHostnameInstead(useThisHostnameInstead);
}
request.setPort(port);
request.setServerStartCode(this.startcode);
request.setServerCurrentTime(now);
这里的rss就是跟master交互的接口
result = rss.regionServerStartup(null, request.build());
这种request.newBuilder().build() builder模式生成请求,然后进行rpc交互,采用google,gRpc协议通信
那怎么知道,哪个类接收到regionserver发起的rpc请求? 直接搜索regionServerStartup方法,看看有哪个类实现了该方法
发现是MasterRpcServices实现了,查看方法实现,只是把regionserver的信息放到一个map里面保存
调用栈:
regionServerStartup
checkAndRecordNewServer
recordNewServerWithLock
/**
* Adds the onlineServers list. onlineServers should be locked.
* @param serverName The remote servers name.
*/
void recordNewServerWithLock(final ServerName serverName, final ServerMetrics sl) {
LOG.info("Registering regionserver=" + serverName);
this.onlineServers.put(serverName, sl);
this.rsAdmins.remove(serverName);
}