分析hadoop源码首先是从启动脚本中寻找调用类
启动脚本路径:
.../hadoop/sbin/start-all.sh
vi star-all.sh 查看脚本内容
# start hdfs daemons if hdfs is present
if [ -f "${HADOOP_HDFS_HOME}"/sbin/start-dfs.sh ]; then
"${HADOOP_HDFS_HOME}"/sbin/start-dfs.sh --config $HADOOP_CONF_DIR
fi
# start yarn daemons if yarn is present
if [ -f "${HADOOP_YARN_HOME}"/sbin/start-yarn.sh ]; then
"${HADOOP_YARN_HOME}"/sbin/start-yarn.sh --config $HADOOP_CONF_DIR
fi
从上面脚本内容可以得出,启动hdfs是从sbin目录下的start-dfs.sh脚本启动的,于是查看start-dfs.sh脚本
#---------------------------------------------------------
# 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是调用了
/sbin/hadoop-daemons.sh +参数,于是转向hadoop-daemons.sh
#################文件内容
bin=`dirname "${BASH_SOURCE-$0}"`
bin=`cd "$bin"; pwd`
DEFAULT_LIBEXEC_DIR="$bin"/../libexec
HADOOP_LIBEXEC_DIR=${HADOOP_LIBEXEC_DIR:-$DEFAULT_LIBEXEC_DIR}
. $HADOOP_LIBEXEC_DIR/hadoop-config.sh
exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_PREFIX" \; "$bin/hadoop-daemon.sh" --config $HADOOP_CONF_DIR "$@"
##################
通过查看shell脚本文件发现 原来是调用了sbin/hadoop-daemon.sh -config hadoop_conf_dir (配置文件的路径)start
于是寻找sbin/hadoop-daemon.sh
hadoop_rotate_log $log
echo starting $command, logging to $log
cd "$HADOOP_PREFIX"
case $command in
namenode|secondarynamenode|datanode|journalnode|dfs|dfsadmin|fsck|balancer|zkfc)
if [ -z "$HADOOP_HDFS_HOME" ]; then
hdfsScript="$HADOOP_PREFIX"/bin/hdfs
else
hdfsScript="$HADOOP_HDFS_HOME"/bin/hdfs
fi
nohup nice -n $HADOOP_NICENESS $hdfsScript --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &
;;
(*)
nohup nice -n $HADOOP_NICENESS $hadoopScript --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &
;;
esac
通过查看上面脚本可以发现最终转向了bin/hdfs这个脚本,所以去查看hdfs这个脚本
if [ "$COMMAND" = "namenode" ] ; then
CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'
# Set SENTRY_HOME if possible and add Sentry plugin jars to classpath
if [[ -z "$SENTRY_HOME" ]]
then
# HADOOP_HDFS_HOME should have been set by hadoop-config.sh
if [[ -d ${HADOOP_HDFS_HOME}/../sentry ]]
then
export SENTRY_HOME=`readlink -m ${HADOOP_HDFS_HOME}/../sentry`
fi
fi
if [[ -n "$SENTRY_HOME" ]]
then
for f in ${SENTRY_HOME}/lib/plugins/*.jar; do
CLASSPATH=${CLASSPATH}:${f}
done
从上面可以看出原来是启动了org.apache.hadoop.hdfs.server.namenode.NameNode这个类
于是打开IDEA,搜索包路径,进入这个包的main函数路口
前面的if主要是做一些参数的校验,
启动namenode是在
NameNode namenode =createNameNode(argv,null);这一句里
最后返回一个new Namenode(conf)
之后,进入这个类
public NameNode(Configuration conf)throws IOException {
this(conf, NamenodeRole.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);
}
进入到initialize方法
namenode是如何启动http服务器对外提供服务的
在启动namenode的时候在main函数里进行参数校验,校验完毕之后,根据模式匹配走到defeut,然后进到namenode构造函数,在namenode构造函数当中,会构造一个initialize(conf)这样一个初始化方法,在这个方法中,会对namenode的角色进行判断,如果当前传递过来的角色是namenode的话,此时开始启动http服务,在启动http服务过程中构建了一个NamenodeHttpServer这个类,然后调用这个类的start方法进行启动,在启动过程中主要干的事情是:在当前的http服务里进行绑定服务,也就是setUpServlets这个方法,在这个方法里不断的绑定需要的功能,然后这个start方法就把这个http服务启动完毕了。其实hadoop是通过建造者模式自己构建了一个HttpServer2。