第一章 Hadoop启动Shell启动脚本分析--基于hadoop-0.20.2-cdh3u1

我的新浪微博:http://weibo.com/freshairbrucewoo

欢迎大家相互交流,共同提高技术。

 

第一章 Hadoop启动Shell启动脚本分析

第一节 start-all.sh脚本

此脚本很简单,就是根据运行此脚本的目录进入安装hadoop目录下的bin目录,然后运行启动hdfsmapred的启动脚本。

bin=`dirname "$0"`
bin=`cd "$bin"; pwd`
. "$bin"/hadoop-config.sh
# start dfs daemons
"$bin"/start-dfs.sh --config $HADOOP_CONF_DIR
# start mapred daemons
"$bin"/start-mapred.sh --config $HADOOP_CONF_DIR

第二节 Start-dfs.sh脚本

此脚本首先检查是否带有参数,代码如下:

if [ $# -ge 1 ]; then
nameStartOpt=$1
shift
case $nameStartOpt in
(-upgrade)
          ;;
        (-rollback)
          dataStartOpt=$nameStartOpt
          ;;
        (*)
            echo $usage
            exit 1
          ;;
      esac
fi

从以上代码可以看出此脚本只支持upgraderollback两个选项参数,一个参数用于更新文件系统,另一个是回滚文件系统。

然后就开始启动namenodedatanodesecondarynamenode节点,执行的脚本代码如下:

"$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

代码中的$HADOOP_CONF_DIR是在另一个脚本中设置的,这个脚本是hadoop-config.sh,后面会详细介绍,因为这个脚本在每一个启动脚本执行中都先执行,目的是为了检查和设置一些环境变量,例如JAVA_HOMEHADOOP_HOME等,而这个脚本又会执行hadoop-env.sh脚本来设置用户配置的相关环境变量,后面详细介绍这两个脚本。

从上面的脚本代码可以看出在启动namenode节点是在hadoop-daemon.sh脚本中启动,下面一节将分析这个脚本。而datanodesecondarynamenode节点的启动又会通过hadoop-daemon.sh脚本来执行。后面也将分析这个脚本的运行情况。

第三节 hadoop-daemon.sh脚本

在具体介绍这个脚本以前先介绍几个环境变量的意义(在这个脚本的注释部分有介绍):

HADOOP_CONF_DIR  选择配置文件目录。默认是${HADOOP_HOME}/conf。
HADOOP_LOG_DIR   存放日志文件的目录。默认是 PWD 命令产生的目录
HADOOP_MASTER    host:path where hadoop code should be rsync'd from
HADOOP_PID_DIR   The pid files are stored. /tmp by default.
HADOOP_IDENT_STRING   A string representing this instance of hadoop. $USER by default
HADOOP_NICENESS The scheduling priority for daemons. Defaults to 0.

这个脚本首先判断所带的参数是否小于1,如果小于就打印使用此脚本的使用帮助,shell代码如下:

usage="Usage: hadoop-daemon.sh [--config <conf-dir>] [--hosts hostlistfile] (start|stop) <had    oop-command> <args...>"
if [ $# -le 1 ]; then
   echo $usage
   exit 1
fi

然后同其他脚本一样执行hadoop-config.sh脚本检查和设置相关环境变量。对于此脚本,hadoop-config.sh脚本的作用就是把配置文件和主机列表的文件处理好了并设置相应的环境变量保存它们。

接着保存启动还是停止的命令和相关参数,如下(注意:shiftshell脚本的作用就是将shell脚本所带参数向前移动一个):

startStop=$1
shift
command=$1
shift

继续就是定义一个用于滚动日志的函数了,具体就不详细分析了。后面是一些根据配置文件中的配置选项来设置前面提到的环境变量,这些环境变量会用于具体启动namenode,例如有调度优先级的环境变量等。

最后就是根据命令还是控制namenode的启停(startstop)了,具体代码如下:

case $startStop in
   (start)
     mkdir -p "$HADOOP_PID_DIR"
     if [ -f $_HADOOP_DAEMON_PIDFILE ]; then
       if kill -0 `cat $_HADOOP_DAEMON_PIDFILE` > /dev/null 2>&1; then
         echo $command running as process `cat $_HADOOP_DAEMON_PIDFILE`.  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 $_HADOOP_DAEMON_OUT
     echo starting $command, logging to $_HADOOP_DAEMON_OUT
     cd "$HADOOP_HOME"
     nice -n $HADOOP_NICENESS "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@    " < /dev/null
     ;;
 
   (stop)
 
     if [ -f $_HADOOP_DAEMON_PIDFILE ]; then
       if kill -0 `cat $_HADOOP_DAEMON_PIDFILE` > /dev/null 2>&1; then
         echo stopping $command
         kill `cat $_HADOOP_DAEMON_PIDFILE`
       else
         echo no $command to stop
       fi
     else
       echo no $command to stop
     fi
     ;;
 
   (*)
     echo $usage
     exit 1
     ;;
esac           
                                                               

如果是start就是启动namenode的命令,那么首先创建存放pid文件的目录,如果存放pid的文件已经存在说明已经有namenode节点已经在运行了,那么就先停止在启动。然后根据日志滚动函数生成日志文件,最后就用nice根据调度优先级启动namenode,但是最终的启动还在另一个脚本hadoop,这个脚本是启动所有节点的终极脚本,它会选择一个带有main函数的类用java启动,这样才到达真正的启动java守护进程的效果,这个脚本是启动的重点,也是我们分析hadoop源码的入口处,所以后面章节重点分析。

如果是stop命令就执行简单的停止命令,其他都是错误的,打印提示使用此脚本的文档。

第四节 hadoop-daemons.shslaves.sh脚本

这个脚本简单,因为他最后也是通过上一节介绍的脚本来启动的,只是在这之前做了一些特殊处理,就是执行另一个脚本slaves.sh代码如下:

exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_HOME" \;"$bin/hadoop-daemon.sh"     --config $HADOOP_CONF_DIR "$@"

Slaves.sh脚本的主要功能就是通过ssh在所有的从节点上运行启动从节点的启动脚本,就是上面代码中的最后两条命令,进入hadoop的目录运行bin目录下的hadoop-daemon.sh脚本。执行这个功能的代码如下:

if [ "$HOSTLIST" = "" ]; then
   if [ "$HADOOP_SLAVES" = "" ]; then
     export HOSTLIST="${HADOOP_CONF_DIR}/slaves"
   else
     export HOSTLIST="${HADOOP_SLAVES}"
   fi
 fi
 
for slave in `cat "$HOSTLIST"|sed  "s/#.*$//;/^$/d"`; do
  ssh $HADOOP_SSH_OPTS $slave {1}quot;${@// /\\ }" \
    2>&1 | sed "s/^/$slave: /" &
  if [ "$HADOOP_SLAVE_SLEEP" != "" ]; then
    sleep $HADOOP_SLAVE_SLEEP
  fi
 done 
 wait

以上代码首先找到所有从节点的主机名称(在slaves文件中,或者配置文件中配置有),然后通过for循环依次通过ssh远程后台运行启动脚本程序,最后等待程序完成才退出此shell脚本。

因此这个脚本主要完成的功能就是在所有从节点执行启动相应节点的脚本。这个脚本执行datanode是从slaves文件中找到datanode节点,执行secondarynamenode是在master文件找到节点主机(在start-dfs.sh脚本中用-hosts master指定的,不然默认会找到slaves文件,datanode就是按默认找到的)。

第五节 start-mapred.sh脚本

这个脚本就两句重要代码,就是分别启动jobtrackertasktracker节点,其他的环境变量还是通过相应的脚本照样设置,如下:

"$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start jobtracker
"$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start tasktracker

从代码可以看出还是通过上一节相同的方式来启动,具体就不在分析了,请看前一节。

第六节 hadoop脚本

这个脚本才是重点,前面的脚本执行都是为这个脚本执行做铺垫的,这个脚本的功能也是相当强大,不仅仅可以启动各个节点的服务,还能够执行很多命令和工具。它会根据传入的参数来决定执行什么样的功能(包括启动各个节点服务),下面详细介绍这个脚本的执行流程和功能。

第一步:切换到bin目录下运行脚本hadoop-config.sh,代码如下:

bin=`dirname "$0"`
bin=`cd "$bin"; pwd`
. "$bin"/hadoop-config.sh

第二步:得到hadoop运行实例的名称和检测运行hadoop的环境是否是windows下的linux模拟环境cygwin,代码如下:

HADOOP_IDENT_STRING=${HADOOP_IDENT_STRING:-$USER}
cygwin=false
case "`uname`" in
CYGWIN*) cygwin=true;;
esac

第三步:判断参数个数是否为0个,是的话打印脚本使用方式并退出,否则就获得具体命令,获得命令的代码如下:

COMMAND=$1
shift

第四步:判断配置文件所在的目录下是否有hadoop-env.sh脚本,有就执行,代码如下:

 if [ -f "${HADOOP_CONF_DIR}/hadoop-env.sh" ]; then
   . "${HADOOP_CONF_DIR}/hadoop-env.sh"
 fi

第五步:设置java执行的相关参数,例如JAVA_HOME变量、运行jvm的最大堆空间等,代码如下:

if [ "$JAVA_HOME" != "" ]; then
  #echo "run java in $JAVA_HOME"
  JAVA_HOME=$JAVA_HOME
fi
if [ "$JAVA_HOME" = "" ]; then
  echo "Error: JAVA_HOME is not set."
  exit 1
fi
JAVA=$JAVA_HOME/bin/java
JAVA_HEAP_MAX=-Xmx1000m
if [ "$HADOOP_HEAPSIZE" != "" ]; then
   JAVA_HEAP_MAX="-Xmx""$HADOOP_HEAPSIZE""m"
fi

第六步:设置CLASSPATH,这一步很重要,因为不设置的话很多类可能找不到,具体设置了那些路径到CLASSPATH看下面的具体代码:

CLASSPATH="${HADOOP_CONF_DIR}"
CLASSPATH=${CLASSPATH}:$JAVA_HOME/lib/tools.jar
if [ "$HADOOP_USER_CLASSPATH_FIRST" != "" ] && [ "$HADOOP_CLASSPATH" != "" ]     ; then
  CLASSPATH=${CLASSPATH}:${HADOOP_CLASSPATH}
fi
if [ -d "$HADOOP_HOME/build/classes" ]; then
  CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/classes
fi
if [ -d "$HADOOP_HOME/build/webapps" ]; then
  CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build
fi
if [ -d "$HADOOP_HOME/build/test/classes" ]; then
  CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/test/classes
fi
if [ -d "$HADOOP_HOME/build/tools" ]; then
  CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/tools
fi

上面代码省略很大一部分,具体还有那些可以看具体的hadoop脚本。

第七步:根据第三步保存的命令选择对应的启动java类,如下:

if [ "$COMMAND" = "classpath" ] ; then
  if $cygwin; then
    CLASSPATH=`cygpath -p -w "$CLASSPATH"`
  fi
  echo $CLASSPATH
  exit
elif [ "$COMMAND" = "namenode" ] ; then
  CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'
  HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"
elif [ "$COMMAND" = "secondarynamenode" ] ; then
  CLASS='org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode'
  HADOOP_OPTS="$HADOOP_OPTS $HADOOP_SECONDARYNAMENODE_OPTS"
elif [ "$COMMAND" = "datanode" ] ; then
  CLASS='org.apache.hadoop.hdfs.server.datanode.DataNode'
  HADOOP_OPTS="$HADOOP_OPTS $HADOOP_DATANODE_OPTS"
elif [ "$COMMAND" = "fs" ] ; then
  CLASS=org.apache.hadoop.fs.FsShell
.....省略很多
elif [[ "$COMMAND" = -*  ]] ; then
  # class and package names cannot begin with a -
  echo "Error: No command named \`$COMMAND' was found. Perhaps you meant \`h    adoop ${COMMAND#-}'"
  exit 1
else
  CLASS=$COMMAND
fi

具体可以执行那些命令从以上代码完全可以看出来,而且执行哪一个命令具体对应哪一个类都很有清楚的对应,让我们在分析某一个具体功能的代码的时候能够很块找到入口点。从上面代码最后第二行可以看出hadoop脚本也可以直接运行一个javajar包或类,这样方便开发者测试自己开发的基于hadoop平台的程序,看样子小脚本能够学到大量知识。

第八步:如果是cygwin环境需要转换路径,代码如下:

if $cygwin; then
   CLASSPATH=`cygpath -p -w "$CLASSPATH"`
   HADOOP_HOME=`cygpath -w "$HADOOP_HOME"`
   HADOOP_LOG_DIR=`cygpath -w "$HADOOP_LOG_DIR"`
   TOOL_PATH=`cygpath -p -w "$TOOL_PATH"`
   JAVA_LIBRARY_PATH=`cygpath -p -w "$JAVA_LIBRARY_PATH"`
 fi

第九步:设置java执行需要的本地库路径JAVA_LIBRARY_PATH,具体代码如下:

if [ -d "${HADOOP_HOME}/build/native" -o -d "${HADOOP_HOME}/lib/native" -o -    d "${HADOOP_HOME}/sbin" ]; then
  JAVA_PLATFORM=`CLASSPATH=${CLASSPATH} ${JAVA} -Xmx32m ${HADOOP_JAVA_PLATFO    RM_OPTS} org.apache.hadoop.util.PlatformName | sed -e "s/ /_/g"`
 
  if [ -d "$HADOOP_HOME/build/native" ]; then
    if [ "x$JAVA_LIBRARY_PATH" != "x" ]; then
        JAVA_LIBRARY_PATH=${JAVA_LIBRARY_PATH}:${HADOOP_HOME}/build/native/$    {JAVA_PLATFORM}/lib
    else
        JAVA_LIBRARY_PATH=${HADOOP_HOME}/build/native/${JAVA_PLATFORM}/lib
    fi
  fi
  if [ -d "${HADOOP_HOME}/lib/native" ]; then
    if [ "x$JAVA_LIBRARY_PATH" != "x" ]; then
      JAVA_LIBRARY_PATH=${JAVA_LIBRARY_PATH}:${HADOOP_HOME}/lib/native/${JAV    A_PLATFORM}
    else
      JAVA_LIBRARY_PATH=${HADOOP_HOME}/lib/native/${JAVA_PLATFORM}
    fi
  fi
  _JSVC_PATH=${HADOOP_HOME}/sbin/${JAVA_PLATFORM}/jsvc
fi
如果是cygwin环境需要转换路径:
if $cygwin; then
  JAVA_LIBRARY_PATH=`cygpath -p "$JAVA_LIBRARY_PATH"`
fi

第十步:设置hadoop可选项变量:HADOOP_OPTS

第十一步:首先判断是运行节点的启动节点运行命令还是普通的客户端命令,然后根据相关条件设置运行的模式(有三种:jvscsunormal),代码如下:

if [[ "$COMMAND" == *node ]] || [[ "$COMMAND" == *tracker ]]; then
  command_uc=$(echo $COMMAND| tr a-z A-Z) #转换为大写
  user_var="HADOOP_${command_uc}_USER"
  _HADOOP_DAEMON_USER=$(eval "echo \$user_var")
  _HADOOP_DAEMON_USER=${_HADOOP_DAEMON_USER:-$(id -un)}
  if [ -z "$_HADOOP_DAEMON_USER" ]; then
    echo Please specify a user to run the $COMMAND by setting $user_var
    exit 1
  elif  [ "$_HADOOP_DAEMON_USER" == "root" ]; then
    echo May not run daemons as root. Please specify $user_var
    exit 1
  fi
  if [ "$EUID" = "0" ] ; then
    if [ "$COMMAND" == "datanode" ] && [ -x "$_JSVC_PATH" ]; then
      _HADOOP_RUN_MODE="jsvc"
    elif [ -x /bin/su ]; then
      _HADOOP_RUN_MODE="su"
    else
      echo "Daemon wants to run as $_HADOOP_DAEMON_USER but script is runnin    g as root"
  echo "and su is not available."
      exit 1
    fi
  else
    if [ "$_HADOOP_DAEMON_USER" != "$(whoami)" ]; then
      echo Daemon wants to run as $_HADOOP_DAEMON_USER but not running as th    at user or root.
      exit 1
    fi
    _HADOOP_RUN_MODE="normal"
  fi
else
  _HADOOP_RUN_MODE="normal"
fi

第十二步:最后一步就是根据上面确定的运行模式具体运行命令,只有datanode节点能够使用jsvc运行,如下代码所示:

case "$_HADOOP_RUN_MODE" in
  jsvc)
    case "$COMMAND" in
      datanode)
        _JSVC_STARTER_CLASS=org.apache.hadoop.hdfs.server.datanode.SecureDat    aNodeStarter
       ;;
       *)
         echo "Cannot start $COMMAND with jsvc"
         exit 1
       ;;
     esac
 
     if [ "$_HADOOP_DAEMON_DETACHED" = "true" ]; then
       _JSVC_FLAGS="-pidfile $_HADOOP_DAEMON_PIDFILE
                   -errfile &1
                   -outfile $_HADOOP_DAEMON_OUT"
     ese
.....省略一些代码,最终执行还是下面这一句代码:
exec "$_JSVC_PATH" -Dproc_$COMMAND \
                        $_JSVC_FLAGS \
                        -user "$_HADOOP_DAEMON_USER" \
                        -cp "$CLASSPATH" \
                        $JAVA_HEAP_MAX $HADOOP_OPTS \
                        $_JSVC_STARTER_CLASS "$@"
   ;;

如果是sunormal模式运行,所有的命令都可以正常的使用java来执行,如下代码:

   normal | su)
     # If we need to su, tack the command into a local variable
     if [ $_HADOOP_RUN_MODE = "su" ]; then
       _JAVA_EXEC="su $_HADOOP_DAEMON_USER -s $JAVA --"
     else
       _JAVA_EXEC="$JAVA"
     fi
     if [ "$_HADOOP_DAEMON_DETACHED" = "true" ]; then
       unset _HADOOP_DAEMON_DETACHED
       touch $_HADOOP_DAEMON_OUT
       nohup $_JAVA_EXEC -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS -classpa    th "$CLASSPATH" $CLASS "$@" > "$_HADOOP_DAEMON_OUT" 2>&1 < /dev/null &
       if [ "$EUID" == "0" ]; then
         chown $_HADOOP_DAEMON_USER $_HADOOP_DAEMON_OUT
       fi
       echo $! > "$_HADOOP_DAEMON_PIDFILE"
       sleep 1
       head "$_HADOOP_DAEMON_OUT"
     else
   exec $_JAVA_EXEC -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS -classpat    h "$CLASSPATH" $CLASS "$@"
     fi
   ;;

到此为止所有脚本执行完毕,剩余就是不能识别模式的错误处理和提示。在执行具体命令的时候可能涉及到用户名的检测,例如su可以指定一个用户名来运行,如果不指定就按照linux上的用户名来运行。

第七节 hadoop-config.shhadoop-env.sh脚本

这两个脚本基本上在上面分析的所有脚本都涉及到,他们的主要功能就是根据命令行参数来设置一些配置文件的路径已经环境变量的值,都是一些公共设置,所以在执行每个脚本的时候都设置一遍。具体的代码就不详细分析了!

第八节 总结

这个启动脚本还是比较复杂,从这个启动脚本我学习到很多知识,第一就是学到很多有关于shell编程的知识,里面很多shell编程的技巧值得学习和借鉴;第二,通过整个启动过程的了解,知道了运行hadoop需要设置的很多东西,包括我们在配置文件中配置的一些选项是怎么起作用的、设置了哪些classpath路径等,第三,详细了解了所有能够通过hadoop执行的命令。还有其他许多收获竟在不言中。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔷薇理想人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值