在启动hadoop的时候,使用start-all.sh shell命令来启动hadoop,那么具体的内部执行流程是怎么样的,有图有真相
接下来我们看下hadoop默认的配置文件的内容
要是有耐心,继续
接着看下hadoop-env.sh 脚本的执行过程
接着会启动dfs
执行start-fds.sh
start-dfs.sh可以单独运行,也可以启动start-all.sh时启动dfs进程。
start-dfs.sh的作用在于启动主节点的namenode,启动secondnamenode,以及各从节点的datanode进程。
脚本注释中有以下三句话:
start-dfs支持upgrage和rollback两个参数,来更改系统的状态。其中upgrage用于升级hdfs文件系统;如果升级失败,可以用rollback对系统进行回滚。具体情况还不太明了。
最后,Run this on master node说明了必须在namenode进程运行的节点上运行该脚本。如果不在core-size.xml文件定义的fs.default.name变量的机器名运行start-dfs.sh或者start-daemon.sh或者hadoop namenode,是无法成功启动namenode守护进程的。已经经过验证。stop-dfs也是一样的。原因:在hadoop脚本中可以看出namenode进程是在本地启动的,所以如果不在core-site.xml定义的节点上运行start-dfs脚本,不会ssh到该节点上去启动namenode。这部分在后续会进行介绍。
由于脚本不长,而且其它脚本前面的处理也一致,所以对这个脚本作详细说明。后面的几个脚本就挑主要部分进行解释。
执行hadoop-daemon.sh脚本
前面三个步骤同上:定义用法说明和脚本的绝对路径、运行配置脚本、处理参数。由于脚本的参数较为重要,首先说明脚本的使用方法。
1)传入参数说明
#说明:定义startStop变量为第一个参数的值。在start-dfs.sh脚本中,调用该脚本时,传入的为’start’。该脚本仅支持start和stop两种。
# get arguments
startStop=$1
#说明:在不了解参数个数和当前要使用的参数个数为第几个的情况,采用shift操作,将使用的参数出栈一位,原来的第二位参数变为第一个,后面仍然用$1来获取本来的第二个参数。
在这里,将start-dfs.sh脚本中,调用该脚本时,传的’namenode’作为command变量的值。
shift
command=$1
shift
2)该脚本使用说明
Usage: hadoop-daemon.sh[--config <conf-dir>] [--hosts hostlistfile] (start|stop)<hadoop-command> <args...>
说明:
--config <conf-dir>指定conf目录的路径;
--hosts hostlistfile:指定hosts,在slaves.sh脚本中,会ssh到该文件中配置的节点上去执行操作。如果没有定义该参数,则默认ssh到slaves文件中定义的节点上去启动后台进程;如果定义该参数,则到定义的机器上去启动后台进程。在start-dfs.sh中,secondarynamenode的启动,就是通过参数—hosts masters来制定获取目的机器的配置文件。
2)确认是否运行secure datanode
作用暂不清楚。
#说明:if中的条件用于判断是否为secure datanode设置,如果是,则后面的三个变量均定义为安全的变量。
if ["$command" == "datanode" ] && [ "$EUID"-eq 0 ] && [ -n "$HADOOP_SECURE_DN_USER" ]; then
exportHADOOP_PID_DIR=$HADOOP_SECURE_DN_PID_DIR
exportHADOOP_LOG_DIR=$HADOOP_SECURE_DN_LOG_DIR
export HADOOP_IDENT_STRING=$HADOOP_SECURE_DN_USER
fi
3)日志目录的创建和处理
#说明:获取日志路径
# get log directory
if ["$HADOOP_LOG_DIR" = "" ]; then
exportHADOOP_LOG_DIR="$HADOOP_HOME/logs"
fi
#说明:mkdir –p创建上层遗失目录。即如果该目录的上层目录也没有,就创建该上层目录。
mkdir -p"$HADOOP_LOG_DIR"
#说明$? ----上一个代码或者shell程序在shell中退出的情况,如果正常退出则返回0,反之为非0值。这里的作用,在于判断log目录中是否可以创建文件并进行文件写操作。
touch$HADOOP_LOG_DIR/.hadoop_test > /dev/null 2>&1
TEST_LOG_DIR=$?
#说明:目的在于测试log dir是否创建成功?即用户是否有权限?如果有,就删除该测试文件。
if ["${TEST_LOG_DIR}" = "0" ]; then
rm -f $HADOOP_LOG_DIR/.hadoop_test
#说明:如果没有,就修改该目录的属性
else
chown $HADOOP_IDENT_STRING $HADOOP_LOG_DIR
fi
#说明:设置log变量为.out文件名
log=$HADOOP_LOG_DIR/hadoop-$HADOOP_IDENT_STRING-$command-$HOSTNAME.out
4)设置pid变量用于存放进程的进程id号
pid的作用在于,判断namenode或者datanode等守护进程是否已经运行。如果已经运行,则打印消息说明已运行;如果没有,则启动守护进程,并将进程id存放在pid文件中,用于下次启动的判断。该过程在start命令的处理流程中。
#说明:获取系统用户名,并存放在HADOOP_IDENT_STRING变量中
if ["$HADOOP_IDENT_STRING" = "" ]; then
export HADOOP_IDENT_STRING="$USER"
fi
#说明:如果没有定义pid文件存放的目录,就设置为/tmp目录
if ["$HADOOP_PID_DIR" = "" ]; then
HADOOP_PID_DIR=/tmp
Fi
#说明:设置pid文件名。根据当前启动的守护进程名称不同而不同。在start-dfs.sh中调用该进程,则pid文件名为/tmp/hadoop-gtl-namenode.pid
pid=$HADOOP_PID_DIR/hadoop-$HADOOP_IDENT_STRING-$command.pid
#说明:设置pid文件名。根据当前启动的守护进程名称不同而不同。在start-dfs.sh中调用该进程,则pid文件名为/tmp/hadoop-gtl-namenode.pid
pid=$HADOOP_PID_DIR/hadoop-$HADOOP_IDENT_STRING-$command.pid
5)启动或停止服务处理(这里只介绍启动)
#说明:在传入参数说明中,已经介绍了startStop参数的定义。在这里,为start,即启动。
case $startStop in
(start)
#说明:创建HADOOP_PID_DIR所定义的pid文件存放的目录
mkdir -p "$HADOOP_PID_DIR"
#说明:如果前面定义的pid变量为文件,则判断当前进程是否存在。如果已经存在,则打印消息,说明服务以及启动,如果要重新启动,需要先停止服务。
if [ -f $pid ]; then
if kill -0 `cat $pid` > /dev/null2>&1; then
echo $command running as process `cat$pid`. Stop it first.
exit 1
fi
fi
#说明:如果定义了HADOOP_MASTER变量,则将日志作镜像备份。其中hadoop_rotate_log是这个脚本中定义的函数,具体可参考hadoop-daemon.sh全文。
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
#说明:进入hadoop根目录,并在系统后台运行hadoop脚本,传入参数为namenode及其参数。并将消息输出到.out日志文件中。真正调用namenode执行实例的内容在hadoop脚本中。
cd "$HADOOP_PREFIX"
nohup nice -n$HADOOP_NICENESS "$HADOOP_PREFIX"/bin/hadoop --config$HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 </dev/null &
#说明:记录该进程的pid,并写入pid变量定义的文件中。
echo $! > $pid
#说明:打印log文件的前10行消息,如果没有错误,则没有消息;如果有错误,则会输出错误信息。
sleep 1; head"$log"
;;
执行hadoop-daemons.sh脚本
前面三个步骤同上:定义用法说明和脚本的绝对路径、运行配置脚本、处理参数。
最后执行以下操作:
#说明:运行slaves.sh,为ssh到各datanode节点和secondarynamenode节点上;
如果是start-dfs调用该脚本传入start datanode来启动datanode服务,会在datanode节点上运行hadoop-daemon.sh start datanode命令
如果是start-dfs调用该脚本传入start secondarynamenode来启动secondarynamenode服务,会在masters定义的节点上运行hadoop-daemon.sh --host masters startsecondarynamenode命令
exec"$bin/slaves.sh" --config $HADOOP_CONF_DIR cd"$HADOOP_HOME" \; "$bin/hadoop-daemon.sh" --config$HADOOP_CONF_DIR "$@"
slaves.sh脚本
前面的步骤同上,不予解释。
1)HADOOP_SLAVES的定义
#说明:如果该变量没有定义,则默认为slaves文件。在hadoop-config文件中,关于HADOOP_SLAVES变量,有专门的处理:如果有—host参数,则HADOOP_SLAVES= ${HADOOP_CONF_DIR}目录下的—host参数后面的参数值。所以在secondarynamenode中,定义的master文件,即为启动secondarynamenode的节点定义文件,而不是通常理解的namenode的启动节点。
if ["$HOSTLIST" = "" ]; then
if [ "$HADOOP_SLAVES" ="" ]; then
export HOSTLIST="${HADOOP_CONF_DIR}/slaves"
else
exportHOSTLIST="${HADOOP_SLAVES}"
fi
fi
2)ssh到各slaves节点上
#说明:读取HADOOP_SLAVES变量的文件的每个slave节点,并用ssh登录到slave节点。
#说明:不匹配注释行和空行。
for slave in `cat"$HOSTLIST"|sed "s/#.*$//;/^$/d"`; do
#说明:这一段脚本的作用在于ssh到目标host后,将在目标节点上的消息打印,并以{hostname: }开头来打印消息。
ssh $HADOOP_SSH_OPTS$slave $"${@// /\\ }" \
2>&1 | sed "s/^/$slave: /"&
if ["$HADOOP_SLAVE_SLEEP" != "" ]; then
sleep $HADOOP_SLAVE_SLEEP
fi
done