• Hadoop的shell脚本分析


    你会发现hadoop-daemon.sh用于启动单独的本机节点

    hadoop-daemons.sh 会批量的ssh到别的机器启动

    前记: 
    这些天一直学习hadoop,学习中也遇到了许多的问题,主要是对hadoop的shell脚本和hadoop的源码概念不够清楚,所以我就对hadoop的bin目录下的shell脚本进行了研究,有一些成果想记录下来,也希望大家前来批评指正。

    分析原因: 
    很多hadoop的初学者对hadoop的脚本不是很清楚,不知道为什么可以在命令行中启动hadoop,也不知道为什么有时在命令行中运行hadoop命令时会出现java的错误。等等这些问题,究其原因我认为是大家对shell脚本不太了解。我曾学过一些shell编程的知识,可是对hadoop的shell程序细节还不是全部了解,我想从宏观上分析一下hadoop脚本的运行流程。

    脚本分析: 
    start-all.sh:

    Java代码  收藏代码
    1. # Start all hadoop daemons.  Run this on master node.  
    2.   
    3. bin=`dirname "$0"`  
    4. bin=`cd "$bin"; pwd`  
    5.   
    6. "$bin"/hadoop-config.sh  
    7.   
    8. # start dfs daemons  
    9. "$bin"/start-dfs.sh --config $HADOOP_CONF_DIR  
    10.   
    11. # start mapred daemons  
    12. "$bin"/start-mapred.sh --config $HADOOP_CONF_DIR  

    分析: 
    正如注释的一样,这个脚本是在master上运行的,即我们运行namenode和jobtracker的主机。它首先启动了hadoop-config.sh脚本,查看hadoop-config.sh,我们可以知道它的作用是对一些变量进行赋值,这些变量有HADOOP_HOME(hadoop的安装目录),HADOOP_CONF_DIR(hadoop的配置文件目录),HADOOP_SLAVES(--hosts指定的文件的地址),为了让大家更好地理解,下面贴出hadoop-config.sh的部分代码

    Java代码  收藏代码
    1. #check to see it is specified whether to use the slaves or the  
    2. # masters file  
    3. if [ $# -gt 1 ]  
    4. then  
    5.     if [ "--hosts" = "$1" ]  
    6.     then  
    7.         shift  
    8.         slavesfile=$1  
    9.         shift  
    10.         export HADOOP_SLAVES="${HADOOP_CONF_DIR}/$slavesfile"  
    11.     fi  

    前面的注释意思是:判断是使用slaves文件,还是master文件,这里为什么要判断呢?那我们带着疑问接着分析下去吧。然后start-all.sh根据hadoop/conf目录下的配置信息启动了start-dfs.sh和start-mapred.sh两个脚本,下面我们去看看这两个脚本又做了些什么吧。

    start-dfs.sh:

    Java代码  收藏代码
    1. # Start hadoop dfs daemons.  
    2. # Optinally upgrade or rollback dfs state.  
    3. # Run this on master node.  
    4.   
    5. usage="Usage: start-dfs.sh [-upgrade|-rollback]"  
    6.   
    7. bin=`dirname "$0"`  
    8. bin=`cd "$bin"; pwd`  
    9.   
    10. "$bin"/hadoop-config.sh  
    11.   
    12. # get arguments  
    13. if [ $# -ge 1 ]; then  
    14.     nameStartOpt=$1  
    15.     shift  
    16.     case $nameStartOpt in  
    17.       (-upgrade)  
    18.         ;;  
    19.       (-rollback)   
    20.         dataStartOpt=$nameStartOpt  
    21.         ;;  
    22.       (*)  
    23.           echo $usage  
    24.           exit 1  
    25.         ;;  
    26.     esac  
    27. fi  
    28.   
    29. # start dfs daemons  
    30. # start namenode after datanodes, to minimize time namenode is up w/o data  
    31. # note: datanodes will log connection errors until namenode starts  
    32. "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start namenode $nameStartOpt  
    33. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start datanode $dataStartOpt  
    34. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR --hosts masters start secondarynamenode  

    分析: 
    根据前面的注释信息,我们发现这个脚本用于启动集群的DFS,我们知道DFS由namenode,datanode,secondarynamenode组成,所以在脚本的最后它又启动了3个进程,分别根据配置文件启动了namenode,datanode,secondarynamenode。其实这个时候你应该已经知道start-mapred.sh干了什么事了。 

    start-mapred.sh:

    Java代码  收藏代码
    1. # Start hadoop map reduce daemons.  Run this on master node.  
    2.   
    3. bin=`dirname "$0"`  
    4. bin=`cd "$bin"; pwd`  
    5.   
    6. "$bin"/hadoop-config.sh  
    7.   
    8. # start mapred daemons  
    9. # start jobtracker first to minimize connection errors at startup  
    10. "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start jobtracker  
    11. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start tasktracker  

    分析: 
    正如你所想,它的作用用于启动mapreduce,所以它的最后同样根据配置文件启动了jobtracker和tasktracker,呵呵,现在发现其实脚本干的事没有想象的那么难了吧。如果你对shell代码看得仔细一点,你会发现hadoop-daemon.sh脚本用于启动namenode和jobtracker,而hadoop-daemons.sh脚本用于启动datanode,secondarynamenode和tasktracker。也就是说hadoop-daemon.sh用于启动master上的进程,而hadoop-daemons.sh用于启动slaves和secondarynamenode主机上的进程(这里考虑的是slaves,secondarynamenode和master配置在了不同主机上的情况)。如果我们分析一下它们俩的代码,你会发现其实它们是有联系的。 

    hadoop-daemons.sh:

    Java代码  收藏代码
    1. # Run a Hadoop command on all slave hosts.  
    2.   
    3. usage="Usage: hadoop-daemons.sh [--config confdir] [--hosts hostlistfile] [start|stop] command args..."  
    4.   
    5. if no args specified, show usage  
    6. if [ $# -le 1 ]; then  
    7.   echo $usage  
    8.   exit 1  
    9. fi  
    10.   
    11. bin=`dirname "$0"`  
    12. bin=`cd "$bin"; pwd`  
    13.   
    14. . $bin/hadoop-config.sh  
    15.   
    16. exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_HOME" ; "$bin/hadoop-daemon.sh" --config $HADOOP_CONF_DIR "$@"  

    分析: 
    看到程序倒数第二行开头的那个exec关键字了吗?它执行了slaves.sh和hadoop-daemon.sh两个脚本,并且把hadoop-daemons.sh命令的参数也传入了hadoop-daemon.sh。呵呵,现在你知道这两个脚本的关系了吧,其实hadoop-daemons.sh中调用了hadoop-daemon.sh,但在调用之前它先执行了slaves.sh脚本,现在你想看看slaves.sh干了啥吗?呵呵,我们也来分析一下吧。 

    slaves.sh:

    Java代码  收藏代码
    1. if [ "$HOSTLIST" = "" ]; then  
    2.   if [ "$HADOOP_SLAVES" = "" ]; then  
    3.     export HOSTLIST="${HADOOP_CONF_DIR}/slaves"  
    4.   else  
    5.     export HOSTLIST="${HADOOP_SLAVES}"  
    6.   fi  
    7. fi  
    8.   
    9. for slave in `cat "$HOSTLIST"|sed  "s/#.*$//;/^$/d"`; do  
    10.  ssh $HADOOP_SSH_OPTS $slave $"${@// /\ }"   
    11.    2>&1 | sed "s/^/$slave: /" &  
    12.  if [ "$HADOOP_SLAVE_SLEEP" != "" ]; then  
    13.    sleep $HADOOP_SLAVE_SLEEP  
    14.  fi  
    15. done  

    分析: 
    由于篇幅问题,以上只贴出了slaves.sh的关键代码,对于启动slaves来说,代码中的HOSTLIST变量是slaves配置文件的地址。再往后看,你会看到非常醒目的一个关键字:ssh,其实这个时候你应该明白了,slave.sh脚本的作用就是通过ssh远程登录到每个在slaves中配置的主机上。所以hadoop-daemons.sh的功能就是先远程登录slaves,在slaves上运行hadoop-daemon.sh脚本。如果你思考的再多一点,那又是怎么启动secondarynamenode的呢?难道也是先远程登录到slaves中配置的主机上吗?答案一定是否定的。而是先远程登录到master中配置的主机上,然后再启动hadoop-daemon.sh脚本,如果你仔细一点,可以看到start-dfs.sh脚本的最后一行命令是启动secondarynamenode,命令传入了“--hosts master”这就指定了按照master中配置的主机来启动secondarynamenode。Hadoop-config.sh负责对“--hosts master”进行解析。

    下面你是不是对hadoop-daemon.sh脚本又产生了兴趣了呢?那我们一起来分析吧。 

    hadoop-daemon.sh:

    Java代码  收藏代码
    1. usage="Usage: hadoop-daemon.sh [--config <conf-dir>] [--hosts hostlistfile] (start|stop) <hadoop-command> <args...>"  
    2.   
    3.   
    4. case $startStop in  
    5.   
    6.   (start)  
    7.   
    8.     mkdir -p "$HADOOP_PID_DIR"  
    9.   
    10.     if [ -f $pid ]; then  
    11.       if kill -0 `cat $pid` > /dev/null 2>&1; then  
    12.         echo $command running as process `cat $pid`.  Stop it first.  
    13.         exit 1  
    14.       fi  
    15.     fi  
    16.   
    17.     if [ "$HADOOP_MASTER" != "" ]; then  
    18.       echo rsync from $HADOOP_MASTER  
    19.       rsync -a -e ssh --delete --exclude=.svn --exclude='logs/*' --exclude='contrib/hod/logs/*' $HADOOP_MASTER/ "$HADOOP_HOME"  
    20.     fi  
    21.   
    22.     hadoop_rotate_log $log  
    23.     echo starting $command, logging to $log  
    24.     cd "$HADOOP_HOME"  
    25.     nohup nice -n $HADOOP_NICENESS "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &  
    26.     echo $! > $pid  
    27.     sleep 1; head "$log"  
    28.     ;;  
    29.             
    30.   (stop)  
    31.   
    32.     if [ -f $pid ]; then  
    33.       if kill -0 `cat $pid` > /dev/null 2>&1; then  
    34.         echo stopping $command  
    35.         kill `cat $pid`  
    36.       else  
    37.         echo no $command to stop  
    38.       fi  
    39.     else  
    40.       echo no $command to stop  
    41.     fi  
    42.     ;;  
    43.   
    44.   (*)  
    45.     echo $usage  
    46.     exit 1  
    47.     ;;  
    48.   
    49. esac  

    分析: 
    以上是hadoop-daemon.sh的关键代码,用于判断执行该脚本时是启动(start)一个进程,还是停止(stop)一个进程。执行该脚本的方式可以查看代码上方的usage变量值(注:[]括起来的表示可有可无,|表示或者,<>括起来表示参数)。这里的<command>参数可以是start或者stop。<command>后面的参数你知道可以是哪些吗?呵呵,其实可以是namenode,jobtracker,secondarynamenode,datanode,tasktracker,如果你在master上自己用hadoop-daemon.sh启动datanode和tasktracker就会有问题,因为hadoop-daemon.sh没有远程登录到slaves主机上哦。执行的结果会在master上启动一个datanode或tasktracker进程,而不是按照slaves配置文件在每个slave上启动datanode和tasktracker哦。

    分析了以上这些脚本之后,我想还有一些脚本,比如说:start-balancer.sh,start-jobhistoryserver.sh就不需要分析了吧。不过看了这些脚本之后,我们发现脚本都是一个执行另一个脚本,到最后都是执行了hadoop-daemon.sh。以启动(start)为例,那hadoop-daemon.sh脚本又是怎么来启动那么多的进程的呢?我们又要回到hadoop-daemon.sh的代码了,之前我们看到hadoop-daemon.sh的一段关键代码是用于判断“启动”还是“停止”进程的,在shell中停止一个进程很方便,用kill命令就可以了,但是该脚本是怎么启动进程的呢?我们继续分析脚本中(start)后面的代码,如果你仔细一点,可以发现其实有这样一段代码:

    Java代码  收藏代码
    1. "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &  

     

    分析: 
    现在你明白我想要说明什么问题了吗,呵呵,其实hadoop-daemon.sh启动进程也是执行了其它的脚本,它就是hadoop/bin/hadoop。其实说到这里hadoop脚本的秘密就快浮出水面了。你还记得博客开头我们提出的问题吗?为什么有时在命令行执行hadoop命令时会出现java的错误信息呢,秘密就在这个hadoop/bin/hadoop脚本里。下面我们来看一下hadoop的核心脚本吧 

    hadoop:

    Java代码  收藏代码
    1. 片段一:  
    2. cygwin=false  
    3. case "`uname`" in  
    4. CYGWIN*) cygwin=true;;  
    5. esac  
    6.   
    7. 片段二:  
    8. for developers, add Hadoop classes to CLASSPATH  
    9. if [ -d "$HADOOP_HOME/build/classes" ]; then  
    10.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/classes  
    11. fi  
    12. if [ -d "$HADOOP_HOME/build/webapps" ]; then  
    13.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build  
    14. fi  
    15. if [ -d "$HADOOP_HOME/build/test/classes" ]; then  
    16.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/test/classes  
    17. fi  
    18. if [ -d "$HADOOP_HOME/build/tools" ]; then  
    19.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/tools  
    20. fi  
    21.   
    22.   
    23. 片段三:  
    24.   
    25. elif [ "$COMMAND" = "namenode" ] ; then  
    26.   CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'  
    27.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"  
    28. elif [ "$COMMAND" = "secondarynamenode" ] ; then  
    29.   CLASS='org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode'  
    30.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_SECONDARYNAMENODE_OPTS"  
    31. elif [ "$COMMAND" = "datanode" ] ; then  
    32.   CLASS='org.apache.hadoop.hdfs.server.datanode.DataNode'  
    33.   
    34. 片段四:  
    35.  exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"  

     

    分析: 
    由于篇幅原因,我只贴出了hadoop脚本具有代表价值的四段代码。下面我们一个个来分析吧

    片段一:
    我们知道在window操作系统上可以通过安装cygwin软件来模拟linux系统环境,这段代码就是用于判断我们的hadoop命令是运行在linux环境上,还是模拟的linux环境上,因为两种情况下文件的路径不相同,hadoop脚本为了区分这两种情况,做出了判断。

    片段二:
    这些操作是将一些目录的路径自动地加到环境变量(CLASSPATH)中。

    片段三:
    其实这个片段才是精华,它根据COMMAND的值给CLASS指定一个对应的java类,

    片段四:
    呵呵,根据CLASS的值,脚本执行了该java类哦,如果你看了hadoop的源码,你会发现,这些类里都有main方法。


    小结: 
    分析到这里,hadoop的shell脚本就全部分析完毕了。如果有不同想法的,希望可以一起交流。

    前记: 
    这些天一直学习hadoop,学习中也遇到了许多的问题,主要是对hadoop的shell脚本和hadoop的源码概念不够清楚,所以我就对hadoop的bin目录下的shell脚本进行了研究,有一些成果想记录下来,也希望大家前来批评指正。

    分析原因: 
    很多hadoop的初学者对hadoop的脚本不是很清楚,不知道为什么可以在命令行中启动hadoop,也不知道为什么有时在命令行中运行hadoop命令时会出现java的错误。等等这些问题,究其原因我认为是大家对shell脚本不太了解。我曾学过一些shell编程的知识,可是对hadoop的shell程序细节还不是全部了解,我想从宏观上分析一下hadoop脚本的运行流程。

    脚本分析: 
    start-all.sh:

    Java代码  收藏代码
    1. # Start all hadoop daemons.  Run this on master node.  
    2.   
    3. bin=`dirname "$0"`  
    4. bin=`cd "$bin"; pwd`  
    5.   
    6. "$bin"/hadoop-config.sh  
    7.   
    8. # start dfs daemons  
    9. "$bin"/start-dfs.sh --config $HADOOP_CONF_DIR  
    10.   
    11. # start mapred daemons  
    12. "$bin"/start-mapred.sh --config $HADOOP_CONF_DIR  

    分析: 
    正如注释的一样,这个脚本是在master上运行的,即我们运行namenode和jobtracker的主机。它首先启动了hadoop-config.sh脚本,查看hadoop-config.sh,我们可以知道它的作用是对一些变量进行赋值,这些变量有HADOOP_HOME(hadoop的安装目录),HADOOP_CONF_DIR(hadoop的配置文件目录),HADOOP_SLAVES(--hosts指定的文件的地址),为了让大家更好地理解,下面贴出hadoop-config.sh的部分代码

    Java代码  收藏代码
    1. #check to see it is specified whether to use the slaves or the  
    2. # masters file  
    3. if [ $# -gt 1 ]  
    4. then  
    5.     if [ "--hosts" = "$1" ]  
    6.     then  
    7.         shift  
    8.         slavesfile=$1  
    9.         shift  
    10.         export HADOOP_SLAVES="${HADOOP_CONF_DIR}/$slavesfile"  
    11.     fi  

    前面的注释意思是:判断是使用slaves文件,还是master文件,这里为什么要判断呢?那我们带着疑问接着分析下去吧。然后start-all.sh根据hadoop/conf目录下的配置信息启动了start-dfs.sh和start-mapred.sh两个脚本,下面我们去看看这两个脚本又做了些什么吧。

    start-dfs.sh:

    Java代码  收藏代码
    1. # Start hadoop dfs daemons.  
    2. # Optinally upgrade or rollback dfs state.  
    3. # Run this on master node.  
    4.   
    5. usage="Usage: start-dfs.sh [-upgrade|-rollback]"  
    6.   
    7. bin=`dirname "$0"`  
    8. bin=`cd "$bin"; pwd`  
    9.   
    10. "$bin"/hadoop-config.sh  
    11.   
    12. # get arguments  
    13. if [ $# -ge 1 ]; then  
    14.     nameStartOpt=$1  
    15.     shift  
    16.     case $nameStartOpt in  
    17.       (-upgrade)  
    18.         ;;  
    19.       (-rollback)   
    20.         dataStartOpt=$nameStartOpt  
    21.         ;;  
    22.       (*)  
    23.           echo $usage  
    24.           exit 1  
    25.         ;;  
    26.     esac  
    27. fi  
    28.   
    29. # start dfs daemons  
    30. # start namenode after datanodes, to minimize time namenode is up w/o data  
    31. # note: datanodes will log connection errors until namenode starts  
    32. "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start namenode $nameStartOpt  
    33. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start datanode $dataStartOpt  
    34. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR --hosts masters start secondarynamenode  

    分析: 
    根据前面的注释信息,我们发现这个脚本用于启动集群的DFS,我们知道DFS由namenode,datanode,secondarynamenode组成,所以在脚本的最后它又启动了3个进程,分别根据配置文件启动了namenode,datanode,secondarynamenode。其实这个时候你应该已经知道start-mapred.sh干了什么事了。 

    start-mapred.sh:

    Java代码  收藏代码
    1. # Start hadoop map reduce daemons.  Run this on master node.  
    2.   
    3. bin=`dirname "$0"`  
    4. bin=`cd "$bin"; pwd`  
    5.   
    6. "$bin"/hadoop-config.sh  
    7.   
    8. # start mapred daemons  
    9. # start jobtracker first to minimize connection errors at startup  
    10. "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start jobtracker  
    11. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start tasktracker  

    分析: 
    正如你所想,它的作用用于启动mapreduce,所以它的最后同样根据配置文件启动了jobtracker和tasktracker,呵呵,现在发现其实脚本干的事没有想象的那么难了吧。如果你对shell代码看得仔细一点,你会发现hadoop-daemon.sh脚本用于启动namenode和jobtracker,而hadoop-daemons.sh脚本用于启动datanode,secondarynamenode和tasktracker。也就是说hadoop-daemon.sh用于启动master上的进程,而hadoop-daemons.sh用于启动slaves和secondarynamenode主机上的进程(这里考虑的是slaves,secondarynamenode和master配置在了不同主机上的情况)。如果我们分析一下它们俩的代码,你会发现其实它们是有联系的。 

    hadoop-daemons.sh:

    Java代码  收藏代码
    1. # Run a Hadoop command on all slave hosts.  
    2.   
    3. usage="Usage: hadoop-daemons.sh [--config confdir] [--hosts hostlistfile] [start|stop] command args..."  
    4.   
    5. if no args specified, show usage  
    6. if [ $# -le 1 ]; then  
    7.   echo $usage  
    8.   exit 1  
    9. fi  
    10.   
    11. bin=`dirname "$0"`  
    12. bin=`cd "$bin"; pwd`  
    13.   
    14. . $bin/hadoop-config.sh  
    15.   
    16. exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_HOME" ; "$bin/hadoop-daemon.sh" --config $HADOOP_CONF_DIR "$@"  

    分析: 
    看到程序倒数第二行开头的那个exec关键字了吗?它执行了slaves.sh和hadoop-daemon.sh两个脚本,并且把hadoop-daemons.sh命令的参数也传入了hadoop-daemon.sh。呵呵,现在你知道这两个脚本的关系了吧,其实hadoop-daemons.sh中调用了hadoop-daemon.sh,但在调用之前它先执行了slaves.sh脚本,现在你想看看slaves.sh干了啥吗?呵呵,我们也来分析一下吧。 

    slaves.sh:

    Java代码  收藏代码
    1. if [ "$HOSTLIST" = "" ]; then  
    2.   if [ "$HADOOP_SLAVES" = "" ]; then  
    3.     export HOSTLIST="${HADOOP_CONF_DIR}/slaves"  
    4.   else  
    5.     export HOSTLIST="${HADOOP_SLAVES}"  
    6.   fi  
    7. fi  
    8.   
    9. for slave in `cat "$HOSTLIST"|sed  "s/#.*$//;/^$/d"`; do  
    10.  ssh $HADOOP_SSH_OPTS $slave $"${@// /\ }"   
    11.    2>&1 | sed "s/^/$slave: /" &  
    12.  if [ "$HADOOP_SLAVE_SLEEP" != "" ]; then  
    13.    sleep $HADOOP_SLAVE_SLEEP  
    14.  fi  
    15. done  

    分析: 
    由于篇幅问题,以上只贴出了slaves.sh的关键代码,对于启动slaves来说,代码中的HOSTLIST变量是slaves配置文件的地址。再往后看,你会看到非常醒目的一个关键字:ssh,其实这个时候你应该明白了,slave.sh脚本的作用就是通过ssh远程登录到每个在slaves中配置的主机上。所以hadoop-daemons.sh的功能就是先远程登录slaves,在slaves上运行hadoop-daemon.sh脚本。如果你思考的再多一点,那又是怎么启动secondarynamenode的呢?难道也是先远程登录到slaves中配置的主机上吗?答案一定是否定的。而是先远程登录到master中配置的主机上,然后再启动hadoop-daemon.sh脚本,如果你仔细一点,可以看到start-dfs.sh脚本的最后一行命令是启动secondarynamenode,命令传入了“--hosts master”这就指定了按照master中配置的主机来启动secondarynamenode。Hadoop-config.sh负责对“--hosts master”进行解析。

    下面你是不是对hadoop-daemon.sh脚本又产生了兴趣了呢?那我们一起来分析吧。 

    hadoop-daemon.sh:

    Java代码  收藏代码
    1. usage="Usage: hadoop-daemon.sh [--config <conf-dir>] [--hosts hostlistfile] (start|stop) <hadoop-command> <args...>"  
    2.   
    3.   
    4. case $startStop in  
    5.   
    6.   (start)  
    7.   
    8.     mkdir -p "$HADOOP_PID_DIR"  
    9.   
    10.     if [ -f $pid ]; then  
    11.       if kill -0 `cat $pid` > /dev/null 2>&1; then  
    12.         echo $command running as process `cat $pid`.  Stop it first.  
    13.         exit 1  
    14.       fi  
    15.     fi  
    16.   
    17.     if [ "$HADOOP_MASTER" != "" ]; then  
    18.       echo rsync from $HADOOP_MASTER  
    19.       rsync -a -e ssh --delete --exclude=.svn --exclude='logs/*' --exclude='contrib/hod/logs/*' $HADOOP_MASTER/ "$HADOOP_HOME"  
    20.     fi  
    21.   
    22.     hadoop_rotate_log $log  
    23.     echo starting $command, logging to $log  
    24.     cd "$HADOOP_HOME"  
    25.     nohup nice -n $HADOOP_NICENESS "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &  
    26.     echo $! > $pid  
    27.     sleep 1; head "$log"  
    28.     ;;  
    29.             
    30.   (stop)  
    31.   
    32.     if [ -f $pid ]; then  
    33.       if kill -0 `cat $pid` > /dev/null 2>&1; then  
    34.         echo stopping $command  
    35.         kill `cat $pid`  
    36.       else  
    37.         echo no $command to stop  
    38.       fi  
    39.     else  
    40.       echo no $command to stop  
    41.     fi  
    42.     ;;  
    43.   
    44.   (*)  
    45.     echo $usage  
    46.     exit 1  
    47.     ;;  
    48.   
    49. esac  

    分析: 
    以上是hadoop-daemon.sh的关键代码,用于判断执行该脚本时是启动(start)一个进程,还是停止(stop)一个进程。执行该脚本的方式可以查看代码上方的usage变量值(注:[]括起来的表示可有可无,|表示或者,<>括起来表示参数)。这里的<command>参数可以是start或者stop。<command>后面的参数你知道可以是哪些吗?呵呵,其实可以是namenode,jobtracker,secondarynamenode,datanode,tasktracker,如果你在master上自己用hadoop-daemon.sh启动datanode和tasktracker就会有问题,因为hadoop-daemon.sh没有远程登录到slaves主机上哦。执行的结果会在master上启动一个datanode或tasktracker进程,而不是按照slaves配置文件在每个slave上启动datanode和tasktracker哦。

    分析了以上这些脚本之后,我想还有一些脚本,比如说:start-balancer.sh,start-jobhistoryserver.sh就不需要分析了吧。不过看了这些脚本之后,我们发现脚本都是一个执行另一个脚本,到最后都是执行了hadoop-daemon.sh。以启动(start)为例,那hadoop-daemon.sh脚本又是怎么来启动那么多的进程的呢?我们又要回到hadoop-daemon.sh的代码了,之前我们看到hadoop-daemon.sh的一段关键代码是用于判断“启动”还是“停止”进程的,在shell中停止一个进程很方便,用kill命令就可以了,但是该脚本是怎么启动进程的呢?我们继续分析脚本中(start)后面的代码,如果你仔细一点,可以发现其实有这样一段代码:

    Java代码  收藏代码
    1. "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &  

     

    分析: 
    现在你明白我想要说明什么问题了吗,呵呵,其实hadoop-daemon.sh启动进程也是执行了其它的脚本,它就是hadoop/bin/hadoop。其实说到这里hadoop脚本的秘密就快浮出水面了。你还记得博客开头我们提出的问题吗?为什么有时在命令行执行hadoop命令时会出现java的错误信息呢,秘密就在这个hadoop/bin/hadoop脚本里。下面我们来看一下hadoop的核心脚本吧 

    hadoop:

    Java代码  收藏代码
    1. 片段一:  
    2. cygwin=false  
    3. case "`uname`" in  
    4. CYGWIN*) cygwin=true;;  
    5. esac  
    6.   
    7. 片段二:  
    8. for developers, add Hadoop classes to CLASSPATH  
    9. if [ -d "$HADOOP_HOME/build/classes" ]; then  
    10.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/classes  
    11. fi  
    12. if [ -d "$HADOOP_HOME/build/webapps" ]; then  
    13.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build  
    14. fi  
    15. if [ -d "$HADOOP_HOME/build/test/classes" ]; then  
    16.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/test/classes  
    17. fi  
    18. if [ -d "$HADOOP_HOME/build/tools" ]; then  
    19.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME/build/tools  
    20. fi  
    21.   
    22.   
    23. 片段三:  
    24.   
    25. elif [ "$COMMAND" = "namenode" ] ; then  
    26.   CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'  
    27.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"  
    28. elif [ "$COMMAND" = "secondarynamenode" ] ; then  
    29.   CLASS='org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode'  
    30.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_SECONDARYNAMENODE_OPTS"  
    31. elif [ "$COMMAND" = "datanode" ] ; then  
    32.   CLASS='org.apache.hadoop.hdfs.server.datanode.DataNode'  
    33.   
    34. 片段四:  
    35.  exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"  

     

    分析: 
    由于篇幅原因,我只贴出了hadoop脚本具有代表价值的四段代码。下面我们一个个来分析吧

    片段一:
    我们知道在window操作系统上可以通过安装cygwin软件来模拟linux系统环境,这段代码就是用于判断我们的hadoop命令是运行在linux环境上,还是模拟的linux环境上,因为两种情况下文件的路径不相同,hadoop脚本为了区分这两种情况,做出了判断。

    片段二:
    这些操作是将一些目录的路径自动地加到环境变量(CLASSPATH)中。

    片段三:
    其实这个片段才是精华,它根据COMMAND的值给CLASS指定一个对应的java类,

    片段四:
    呵呵,根据CLASS的值,脚本执行了该java类哦,如果你看了hadoop的源码,你会发现,这些类里都有main方法。


    小结: 
    分析到这里,hadoop的shell脚本就全部分析完毕了。如果有不同想法的,希望可以一起交流。

  • 相关阅读:
    Java 连oracle 12C 起步
    powershell excel 导入 sqlserver
    移动端适配方案(上)
    ie7兼容问题
    node学习第三天(2)
    node学习第三天(1)
    HTMl5的sessionStorage和localStorage的一些区别
    html5+css3实战之-幽灵按钮
    node.js理论知识梳理
    node.js学习第二天
  • 原文地址:https://www.cnblogs.com/zlingh/p/4307879.html
Copyright © 2020-2023  润新知