目录
1. 概述
我们要分析HDFS-NameNode的启动流程,就得从启动脚本开始一步步分析,当然开始之前,我们需要编译Hadoop的源码,具体的编译流程请参考我另外一篇博客 hadoop2.6.5源码编译。
2. start-dfs.sh
2.1. 介绍
我们启动Hadoop在2.6版本是通过 start-dfs.sh
来启动的。
start-dfs.sh
的使用说明为 usage="Usage: start-dfs.sh [-upgrade|-rollback] [other options such as -clusterId]"
当不传递任何参数的时候,该脚本会依次启动 NameNode
,DataNodes
,SecondaryNamenode
,JournalNodes
,ZKFailoverControllers
这里我们只看NameNode
.
2.2. 分析脚本源码
1 2 3 4 5 6 7 8 9 10 11 12 |
#--------------------------------------------------------- # namenodes NAMENODES=$($HADOOP_PREFIX/bin/hdfs getconf -namenodes) echo "Starting namenodes on [$NAMENODES]" "$HADOOP_PREFIX/sbin/hadoop-daemons.sh" \ --config "$HADOOP_CONF_DIR" \ --hostnames "$NAMENODES" \ --script "$bin/hdfs" start namenode $nameStartOpt |
这里主要就是加载一下配置文件,获取Namenode配置节点,并调用 hadoop-daemons.sh脚本来运行核心的 hdfs start namenode。
我们来看下 bin/hdfs 脚本,核心脚本如下:
1 2 3 4 5 6 |
if [ "$COMMAND" = "namenode" ] ; then CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode' HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS" ...... exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@" |
发现直接会去启动 org.apache.hadoop.hdfs.server.namenode.NameNode
这个类,剩下的我们可以直接看 hadoop 该类的main()
方法源码了。
3. org.apache.hadoop.hdfs.server.namenode.NameNode源码
3.1. main方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public static void main(String argv[]) throws Exception { if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) { System.exit(0); } try { StringUtils.startupShutdownMessage(NameNode.class, argv, LOG); NameNode namenode = createNameNode(argv, null); if (namenode != null) { namenode.join(); } } catch (Throwable e) { LOG.fatal("Failed to start namenode.", e); terminate(1, e); } } |
其中核心的代码是 NameNode namenode = createNameNode(argv, null);
3.2. createNameNode(String argv[], Configuration conf) 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public static NameNode createNameNode(String argv[], Configuration conf) throws IOException { LOG.info("createNameNode " + Arrays.asList(argv)); if (conf == null) conf = new HdfsConfiguration(); // Parse out some generic args into Configuration. GenericOptionsParser hParser = new GenericOptionsParser(conf, argv); argv = hParser.getRemainingArgs(); // Parse the rest, NN specific args. StartupOption startOpt = parseArguments(argv); if (startOpt == null) { printUsage(System.err); return null; } setStartupOption(conf, startOpt); switch (startOpt) { case FORMAT: {} case ROLLBACK: {} ......// 省略 default: { DefaultMetricsSystem.initialize("NameNode"); return new NameNode(conf); } } |
大致上上面就是检查一下配置文件,输出一些日志。然后核心的是 switch 代码块中,根据启动参数来判断具体要做对应的事情,然而我们调用 start-dfs.sh -> hdfs start namenode
是没有带任何参数的,所以这里直接回调用 default
中的代码块,这中间最核心的是 new NameNode(conf)
3.3. NameNode构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public NameNode(Configuration conf) throws IOException { this(conf, NamenodeRole.NAMENODE); } protected NameNode(Configuration conf, NamenodeRole role) throws IOException { this.conf = conf; this.role = role; setClientNamenodeAddress(conf); String nsId = getNameServiceId(conf); String namenodeId = HAUtil.getNameNodeId(conf, nsId); this.haEnabled = HAUtil.isHAEnabled(conf, nsId); state = createHAState(getStartupOption(conf)); this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf); this.haContext = createHAContext(); try { initializeGenericKeys(conf, nsId, namenodeId); initialize(conf); 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); } |
createNameNode
方法中调用的NameNode构造方法,这其中最核心的是 initialize(conf);
方法,这就开始真正的NameNode
启动核心流程的最重要方法了。
3.4. initialize 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/** * Initialize name-node. * 初始化Namenode的核心逻辑 * @param conf the configuration */ protected void initialize(Configuration conf) throws IOException { if (conf.get(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS) == null) { String intervals = conf.get(DFS_METRICS_PERCENTILES_INTERVALS_KEY); if (intervals != null) { conf.set(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS, intervals); } } UserGroupInformation.setConfiguration(conf); loginAsNameNodeUser(conf); NameNode.initMetrics(conf, this.getRole()); StartupProgressMetrics.register(startupProgress); if (NamenodeRole.NAMENODE == role) { // 启动NameNode Web服务,地址为 0.0.0.0:50070 startHttpServer(conf); } this.spanReceiverHost = SpanReceiverHost.getInstance(conf); // 初始化FSNamesystem,磁盘加载fsimage、edits log 并进行内存合并 loadNamesystem(conf); // 初始化RPCServer,接收各组件发过来的RPC轻轻 rpcServer = createRpcServer(conf); if (clientNamenodeAddress == null) { // This is expected for MiniDFSCluster. Set it now using // the RPC server's bind address. clientNamenodeAddress = NetUtils.getHostPortString(rpcServer.getRpcAddress()); LOG.info("Clients are to use " + clientNamenodeAddress + " to access" + " this namenode/service."); } if (NamenodeRole.NAMENODE == role) { httpServer.setNameNodeAddress(getNameNodeAddress()); httpServer.setFSImage(getFSImage()); } pauseMonitor = new JvmPauseMonitor(conf); pauseMonitor.start(); metrics.getJvmMetrics().setPauseMonitor(pauseMonitor); // 检查安全模式,启动后台线程 startCommonServices(conf); } |
4. 总结
整个启动流程不是特别复杂,其实就是启动一个httpServer来提供HDFS Web界面,然后启动一个RPCServer,一堆后台线程,检查磁盘空间和SafeMode控制。启动这些组件启动完成,就可以让Datanode等其他组件之后来找NameNode注册,让NameNode感知到集群的所有DataNode。
1 2 3 4 5 6 7 8 9 10 11 12 |
NameNode.initialize() -> 初始化的核心逻辑 -> startHttpServer() -> 启动自己的http服务器,后面接收别人发送过来的http请求 -> loadNamesystem() -> 初始化FSNamesystem,磁盘加载fsimage和edits进行内存合并 -> createRpcServer() -> 初始化rpc server,接收别人调用过来的rpc请求 -> startCommonServices() -> FSNamesystem.startCommonServices() -> checkAvailableResources() -> 检查磁盘空间是否有100m来写入edits log -> setBlockTotal() -> 检查是否要进入safemode -> BlockManager.active() -> 启动一堆后台线程,做一些任务 -> NameNodeRpcServer.start() -> 启动rpc server NameNode.join() -> 等待rpc server结束,理论上永远不会结束的 |
原创文章,转载请注明: 转载自LoserZhao – 诗和远方[ http://www.loserzhao.com/ ]
本文链接地址: http://www.loserzhao.com/bigdata/hadoop2-6-5-source-analysis-namenode-core-start-process.html
文章的脚注信息由WordPress的wp-posturl插件自动生成
0 条评论。