今天来看下hadoop dfs 的启动过程都做了些什么。
启动hdfs的时候,一般都是使用命令./start-dfs.sh,那就从这个sh文件入手:
"$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start namenode $nameStartOpt "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start datanode $dataStartOpt "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR --hosts masters start secondarynamenode
在脚本的最后调用了这3命令,分别是启动namenode,datanode和secondarynamenode。
接着看hadoop-daemon.sh脚本:
case $startStop in (start) mkdir -p "$HADOOP_PID_DIR" if [ -f $pid ]; then if kill -0 `cat $pid` > /dev/null 2>&1; then echo $command running as process `cat $pid`. Stop it first. exit 1 fi fi if [ "$HADOOP_MASTER" != "" ]; then echo rsync from $HADOOP_MASTER rsync -a -e ssh --delete --exclude=.svn --exclude='logs/*' --exclude='contrib/hod/logs/*' $HADOOP_MASTER/ "$HADOOP_HOME" fi hadoop_rotate_log $log echo starting $command, logging to $log cd "$HADOOP_PREFIX" //关键的在这里,又去调用hadoop这个脚本 nohup nice -n $HADOOP_NICENESS "$HADOOP_PREFIX"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null & echo $! > $pid sleep 1; head "$log" ;;
看到上面的代码,发现这里有执行了hadoop这个脚本,执行了命令hadoop --config configfile namenode,接着看hadoop的脚本吧:
elif [ "$COMMAND" = "namenode" ] ; then CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode' HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"
终于找到了启动namenode所调用的类了,同样的流程,也可以找到datanode,secondarynamenode的启动类。
接着看NameNode类:
在注释中看到:
* The NameNode controls two critical tables:
* 1) filename->blocksequence (namespace)
* 2) block->machinelist ("inodes")
namenode维护了2个关键表,一个是文件和块序列的对应关系,一个是块和datanode对象关系,就是保存了一个文件对应了哪些块,一个块存储在哪些机器上。
首先通过main方法
public static void main(String argv[]) throws Exception { try { StringUtils.startupShutdownMessage(NameNode.class, argv, LOG); NameNode namenode = createNameNode(argv, null); if (namenode != null) namenode.join(); } catch (Throwable e) { LOG.error(StringUtils.stringifyException(e)); System.exit(-1); } }
调用createNameNode方法创建namenode,该方法中通过NameNode namenode = new NameNode(conf)来创建,再看看构造方法中调用了 initialize(conf),截取initialize方法中一些主要的内容:
............. this.namesystem = new FSNamesystem(this, conf); .............
FSNamesystem才是用来保存有节点信息的,包括:
1) valid fsname --> blocklist (kept on disk, logged)
* 2) Set of all valid blocks (inverted #1)
* 3) block --> machinelist (kept in memory, rebuilt dynamically from reports)
* 4) machine --> blocklist (inverted #2)
* 5) LRU cache of updated-heartbeat machines
加载fsimge,edits,启动监听进程接收datanode的信息,启动rpc底层通信服务,namenode的启动主要就是做的这些事情,可以看到主要工作在加载fsimage,和接收datanode的信息。如果fsimage比较大的话,那么启动过程会较慢,同样,如果集群比较大,那么接收datanode的block信息同样也是非常耗时的地方。
关于加载fsimge和datanode的rpc通信下一次在分析吧。