003-hadoop二次开发-NameNode启动流程
main函数
一旦调用org.apache.hadoop.hdfs.server.namenode.NameNode,那么在该类下一定有个main函数。
启动NameNode需要提交参数,首先对参数要进行合法校验,
if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
System.out.println("####参数校验#####");
System.exit(0);
//hadooop namenode -format
//hadoop -datemon.sh start namenode
//hadoop-datemon.sh start nn
}
然后启动打印日志,
try {
//启动打印日志
StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
//TODO 创建NameNode核心代码
NameNode namenode = createNameNode(argv, null);
if (namenode != null) {
//就是线程的join
//会使主线程进入等待池并等待t线程执行完毕后才会被唤醒
namenode.join();
}
} catch (Throwable e) {
LOG.error("Failed to start namenode.", e);
terminate(1, e);
}
通过createNameNode(argv, null)进入,
if (conf == null)
conf = new HdfsConfiguration();
StartupOption startOpt = parseArguments(argv);
首先判断配置文件是否为空,如果为空创建一个配置文件,然后去解析传进的配置参数,传进去是一些参数字符串,要解析成枚举等变量,在parseArguments(argv)中进行解析,返回StartupOption 。(ctrl+alt+左箭头返回上一步操作处)
if (startOpt == null) {
printUsage(System.err);
return null;
}
如果没有解析StartupOption打印异常,
//将启动参数加入到配置中
setStartupOption(conf, startOpt);
private static void setStartupOption(Configuration conf, StartupOption opt) {
conf.set(DFS_NAMENODE_STARTUP_KEY, opt.name());
}
如果解析出StartupOption,将参数加入配置中,设置初始化参数。
接下来switch模式匹配进行模式判断,
/**
* 我们在集群中操作 , 比如 :
* hdfs namenode -format
* hadoop fs -put XXX /
* 正常情况下,是先启动namenode
* hadoop-daemon.sh start namenode
* */
switch (startOpt) {
//格式化
case FORMAT: {//hadoop namenode -format
boolean aborted = format(conf, startOpt.getForceFormat(),
startOpt.getInteractiveFormat());
terminate(aborted ? 1 : 0);
return null; // avoid javac warning
}
// 产生集群ID.
case GENCLUSTERID: {
System.err.println("Generating new cluster id:");
System.out.println(NNStorage.newClusterID());
terminate(0);
return null;
}
//定版本
case FINALIZE: {
System.err.println("Use of the argument '" + StartupOption.FINALIZE +
"' is no longer supported. To finalize an upgrade, start the NN " +
" and then run `hdfs dfsadmin -finalizeUpgrade'");
terminate(1);
return null; // avoid javac warning
}
//回滚
case ROLLBACK: {
boolean aborted = doRollback(conf, true);
terminate(aborted ? 1 : 0);
return null; // avoid warning
}
//同步active节点的快照(配置完HA需要运行这个命令同步active节点的快照(配置完HA需要运行这个命令
case BOOTSTRAPSTANDBY: {
String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length);
int rc = BootstrapStandby.run(toolArgs, conf);
terminate(rc);
return null; // avoid warning
}
//向备用节点共享一组edits日志
case INITIALIZESHAREDEDITS: {
boolean aborted = initializeSharedEdits(conf,
startOpt.getForceFormat(),
startOpt.getInteractiveFormat());
terminate(aborted ? 1 : 0);
return null; // avoid warning
}
//启动冷备或者温备名字节点
case BACKUP:
case CHECKPOINT: {
NamenodeRole role = startOpt.toNodeRole();
DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));
return new BackupNode(conf, role);
}
//恢复损坏的元数据以及文件系统
case RECOVER: {
NameNode.doRecovery(startOpt, conf);
return null;
}
//检查配置的正确性
case METADATAVERSION: {
printMetadataVersion(conf);
terminate(0);
return null; // avoid javac warning
}
//以升级的方式启动
case UPGRADEONLY: {
DefaultMetricsSystem.initialize("NameNode");
new NameNode(conf);
terminate(0);
return null;
}
//正常启动NameNode
default: {
//初始化metric系统(所有大数据框都依赖于metric)
//通过metric监控启动时长,某个任务消耗时间等
DefaultMetricsSystem.initialize("NameNode");
//TODO
return new NameNode(conf);
}
}
通过new NameNode(conf)走到
public NameNode(Configuration conf) throws IOException {
this(conf, NamenodeRole.NAMENODE);
}
通过this走到namenode核心领域,
/**
* 1、对namenode做参数的注册(fs.defaultFS、rpc地址等)
* 2、初始化
* 3、根据初始化处理的结果,namenode进入对应的状态(active、backup、standby)
* */
protected NameNode(Configuration conf, NamenodeRole role)
throws IOException {
this.conf = conf;
this.role = role;//保存NameNode的角色信息
//设置clients访问nomenode或nameservice的访问地址 配置项fs.defaultFS:hadoop01:9000
setClientNamenodeAddress(conf);
String nsId = getNameServiceId(conf);
String namenodeId = HAUtil.getNameNodeId(conf, nsId);
//ha相关
this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
//根据用户设置的启动参数,确定启动以后的初始状态,如果是正常启动,则全部直接进入Standby状态
state = createHAState(getStartupOption(conf));
this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
//TODO 在创建HA的时候,也启动了standByNameNode的服务
this.haContext = createHAContext();
try {
//给联邦模式下准备的,主要是设置联邦模式下namenode的地址和RPC地址
initializeGenericKeys(conf, nsId, namenodeId);
//TODO
initialize(conf);
// HA相关
try {
haContext.writeLock();
state.prepareToEnterState(haContext);
state.enterState(haContext);
} finally {
haContext.writeUnlock();
}
} catch (IOException e) {
this.stop();
throw e;
} catch (HadoopIllegalArgumentException e) {
this.stop();
throw e;
}
this.started.set(true);
}