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:
- # Start all hadoop daemons. Run this on master node.
- 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
分析:
正如注释的一样,这个脚本是在master上运行的,即我们运行namenode和jobtracker的主机。它首先启动了hadoop-config.sh脚本,查看hadoop-config.sh,我们可以知道它的作用是对一些变量进行赋值,这些变量有HADOOP_HOME(hadoop的安装目录),HADOOP_CONF_DIR(hadoop的配置文件目录),HADOOP_SLAVES(--hosts指定的文件的地址),为了让大家更好地理解,下面贴出hadoop-config.sh的部分代码
- #check to see it is specified whether to use the slaves or the
- # masters file
- if [ $# -gt 1 ]
- then
- if [ "--hosts" = "$1" ]
- then
- shift
- slavesfile=$1
- shift
- export HADOOP_SLAVES="${HADOOP_CONF_DIR}/$slavesfile"
- fi
前面的注释意思是:判断是使用slaves文件,还是master文件,这里为什么要判断呢?那我们带着疑问接着分析下去吧。然后start-all.sh根据hadoop/conf目录下的配置信息启动了start-dfs.sh和start-mapred.sh两个脚本,下面我们去看看这两个脚本又做了些什么吧。
start-dfs.sh:
- # Start hadoop dfs daemons.
- # Optinally upgrade or rollback dfs state.
- # Run this on master node.
- usage="Usage: start-dfs.sh [-upgrade|-rollback]"
- bin=`dirname "$0"`
- bin=`cd "$bin"; pwd`
- . "$bin"/hadoop-config.sh
- # get arguments
- if [ $# -ge 1 ]; then
- nameStartOpt=$1
- shift
- case $nameStartOpt in
- (-upgrade)
- ;;
- (-rollback)
- dataStartOpt=$nameStartOpt
- ;;
- (*)
- echo $usage
- exit 1
- ;;
- esac
- fi
- # start dfs daemons
- # start namenode after datanodes, to minimize time namenode is up w/o data
- # note: datanodes will log connection errors until namenode starts
- "$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
分析:
根据前面的注释信息,我们发现这个脚本用于启动集群的DFS,我们知道DFS由namenode,datanode,secondarynamenode组成,所以在脚本的最后它又启动了3个进程,分别根据配置文件启动了namenode,datanode,secondarynamenode。其实这个时候你应该已经知道start-mapred.sh干了什么事了。
start-mapred.sh:
- # Start hadoop map reduce daemons. Run this on master node.
- bin=`dirname "$0"`
- bin=`cd "$bin"; pwd`
- . "$bin"/hadoop-config.sh
- # start mapred daemons
- # start jobtracker first to minimize connection errors at startup
- "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start jobtracker
- "$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:
- # Run a Hadoop command on all slave hosts.
- usage="Usage: hadoop-daemons.sh [--config confdir] [--hosts hostlistfile] [start|stop] command args..."
- # if no args specified, show usage
- if [ $# -le 1 ]; then
- echo $usage
- exit 1
- fi
- bin=`dirname "$0"`
- bin=`cd "$bin"; pwd`
- . $bin/hadoop-config.sh
- 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:
- 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 $"${@// /\\ }" \
- 2>&1 | sed "s/^/$slave: /" &
- if [ "$HADOOP_SLAVE_SLEEP" != "" ]; then
- sleep $HADOOP_SLAVE_SLEEP
- fi
- 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:
- usage="Usage: hadoop-daemon.sh [--config <conf-dir>] [--hosts hostlistfile] (start|stop) <hadoop-command> <args...>"
- 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_HOME"
- nohup nice -n $HADOOP_NICENESS "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &
- echo $! > $pid
- sleep 1; head "$log"
- ;;
- (stop)
- if [ -f $pid ]; then
- if kill -0 `cat $pid` > /dev/null 2>&1; then
- echo stopping $command
- kill `cat $pid`
- else
- echo no $command to stop
- fi
- else
- echo no $command to stop
- fi
- ;;
- (*)
- echo $usage
- exit 1
- ;;
- 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)后面的代码,如果你仔细一点,可以发现其实有这样一段代码:
- "$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:
- 片段一:
- cygwin=false
- case "`uname`" in
- CYGWIN*) cygwin=true;;
- esac
- 片段二:
- # for developers, add Hadoop classes to CLASSPATH
- 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
- 片段三:
- 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'
- 片段四:
- 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:
- # Start all hadoop daemons. Run this on master node.
- 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
分析:
正如注释的一样,这个脚本是在master上运行的,即我们运行namenode和jobtracker的主机。它首先启动了hadoop-config.sh脚本,查看hadoop-config.sh,我们可以知道它的作用是对一些变量进行赋值,这些变量有HADOOP_HOME(hadoop的安装目录),HADOOP_CONF_DIR(hadoop的配置文件目录),HADOOP_SLAVES(--hosts指定的文件的地址),为了让大家更好地理解,下面贴出hadoop-config.sh的部分代码
- #check to see it is specified whether to use the slaves or the
- # masters file
- if [ $# -gt 1 ]
- then
- if [ "--hosts" = "$1" ]
- then
- shift
- slavesfile=$1
- shift
- export HADOOP_SLAVES="${HADOOP_CONF_DIR}/$slavesfile"
- fi
前面的注释意思是:判断是使用slaves文件,还是master文件,这里为什么要判断呢?那我们带着疑问接着分析下去吧。然后start-all.sh根据hadoop/conf目录下的配置信息启动了start-dfs.sh和start-mapred.sh两个脚本,下面我们去看看这两个脚本又做了些什么吧。
start-dfs.sh:
- # Start hadoop dfs daemons.
- # Optinally upgrade or rollback dfs state.
- # Run this on master node.
- usage="Usage: start-dfs.sh [-upgrade|-rollback]"
- bin=`dirname "$0"`
- bin=`cd "$bin"; pwd`
- . "$bin"/hadoop-config.sh
- # get arguments
- if [ $# -ge 1 ]; then
- nameStartOpt=$1
- shift
- case $nameStartOpt in
- (-upgrade)
- ;;
- (-rollback)
- dataStartOpt=$nameStartOpt
- ;;
- (*)
- echo $usage
- exit 1
- ;;
- esac
- fi
- # start dfs daemons
- # start namenode after datanodes, to minimize time namenode is up w/o data
- # note: datanodes will log connection errors until namenode starts
- "$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
分析:
根据前面的注释信息,我们发现这个脚本用于启动集群的DFS,我们知道DFS由namenode,datanode,secondarynamenode组成,所以在脚本的最后它又启动了3个进程,分别根据配置文件启动了namenode,datanode,secondarynamenode。其实这个时候你应该已经知道start-mapred.sh干了什么事了。
start-mapred.sh:
- # Start hadoop map reduce daemons. Run this on master node.
- bin=`dirname "$0"`
- bin=`cd "$bin"; pwd`
- . "$bin"/hadoop-config.sh
- # start mapred daemons
- # start jobtracker first to minimize connection errors at startup
- "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start jobtracker
- "$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:
- # Run a Hadoop command on all slave hosts.
- usage="Usage: hadoop-daemons.sh [--config confdir] [--hosts hostlistfile] [start|stop] command args..."
- # if no args specified, show usage
- if [ $# -le 1 ]; then
- echo $usage
- exit 1
- fi
- bin=`dirname "$0"`
- bin=`cd "$bin"; pwd`
- . $bin/hadoop-config.sh
- 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:
- 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 $"${@// /\\ }" \
- 2>&1 | sed "s/^/$slave: /" &
- if [ "$HADOOP_SLAVE_SLEEP" != "" ]; then
- sleep $HADOOP_SLAVE_SLEEP
- fi
- 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:
- usage="Usage: hadoop-daemon.sh [--config <conf-dir>] [--hosts hostlistfile] (start|stop) <hadoop-command> <args...>"
- 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_HOME"
- nohup nice -n $HADOOP_NICENESS "$HADOOP_HOME"/bin/hadoop --config $HADOOP_CONF_DIR $command "$@" > "$log" 2>&1 < /dev/null &
- echo $! > $pid
- sleep 1; head "$log"
- ;;
- (stop)
- if [ -f $pid ]; then
- if kill -0 `cat $pid` > /dev/null 2>&1; then
- echo stopping $command
- kill `cat $pid`
- else
- echo no $command to stop
- fi
- else
- echo no $command to stop
- fi
- ;;
- (*)
- echo $usage
- exit 1
- ;;
- 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)后面的代码,如果你仔细一点,可以发现其实有这样一段代码:
- "$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:
- 片段一:
- cygwin=false
- case "`uname`" in
- CYGWIN*) cygwin=true;;
- esac
- 片段二:
- # for developers, add Hadoop classes to CLASSPATH
- 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
- 片段三:
- 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'
- 片段四:
- 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的shell脚本分析的更多相关文章
- shell脚本分析nginx日志
shell脚本分析nginx日志: name=`awk -F ',' '{print $13":"$32}' $file | awk -F ':' '{print $4}'`ech ...
- 使用shell脚本分析Nagios的status.dat文件
前言 Nagios的安装和配置以及批量添加监控服务器在我前面的文章中已经讲的很详细了. 我们知道,Nagios的网页控制页面(一般为http://nagio.domain.com/nagios)里可以 ...
- 一段shell脚本分析
工作中碰到这样的需求: 1.每天定时要执行python脚本生成excel 2.将生成的excel拷贝到特定目录下 3.通过python发送脚本发送给特定的接收者 因为之前没有接触过shell脚本,同事 ...
- shell脚本分析 nginx日志访问次数最多及最耗时的页面
当服务器压力比较大,跑起来很费力时候.我们经常做站点页面优化,会去查找那些页面访问次数比较多,而且比较费时. 找到那些访问次数高,并且比较耗时的地址,就行相关优化,会取得立竿见影的效果的. 下面是我在 ...
- Shell脚本分析服务器性能
概述 我们原先在服务器上想分析性能指标,需要执行一系列的linux命令.对于linux命令不熟悉的人来说,比较困难 现在有一套集成的shell脚本,把常用的linux命令都包含在里面,一键式分析性能瓶 ...
- shell脚本分析一
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言.Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界 ...
- Hadoop1.2.1 启停的Shell 脚本分析
停止shell脚本以此类推.
- 如何用shell脚本分析网站日志统计PV、404、500等数据
以下shell脚本能统计出网站的总访问量,以及404,500出现的次数.统计出来后,可以结合监控宝来进行记录,进而可以看出网站访问量是否异常,是否存在攻击.还可以根据查看500出现的次数,进而判断网站 ...
- shell脚本分析二
Shell 基本运算符Shell 和其他编程语言一样,支持多种运算符,包括: 算数运算符 关系运算符 布尔运算符 字符串运算符 文件测试运算符原生bash不支持简单的数学运算,但是可以通过其他命令来实 ...
随机推荐
- Map的3种遍历[轉]
Map<String, String> map = new HashMap<String, String>(); map.put("A", "AA ...
- Maven依赖(转)
相同依赖级别,先加入的先依赖不同依赖级别,级别短的先依赖 version-->SNAPSHOTxxx-里程碑-->SNAPSHOT,alpha,beta,Release(RC),GA()s ...
- css 选择器优先级的计算过程
以下转自互联网 下面看看官方对选择器的定义:一个选择器的优先级由四个数字a,b,c,d确定.当比较两个选择器时,先比较a,a值大的优先级高,如果a相等则比较b,b值大的优先级高,以此类推.因此,无论b ...
- 使用NodeJS将XML解析成JSON及性能比较
并不是所有的API都是以JSON格式返回的.我们有时侯不得不处理一些XML.幸运的是有一个NodeJS模块 xml2js 可以帮你做这件事. 比如,我们要处理下面这段XML <?xml ...
- 查看Oracle的SID用户名等信息
源地址:http://zhidao.baidu.com/question/681563406501077052.html 用sysdba身份登录 比如 conn /as sysdba 匿名管理员登陆 ...
- [Flex] ButtonBar系列——labelFunction用户提供的函数,在每个项目上运行以确定其标签
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ...
- [Java] java中的接口定义
在Java的通常规范中,对数据成员的修改要通过接口提供的方法进行(如下面示例中接口中的void learnMath(int hours)和void learnEnglish(int hours)),这 ...
- 九度OJ1468
这道题其实就是个很简单的静态链表,需要注意的是,地址一共有5位,最后输出的时候如果之前是使用int类型存储地址的话,一定要强制规定输出的位数(5位),否则有可能会将高位省略.(如地址00001输出为1 ...
- Redis多机功能之复制
复制的目的:创建具有相同数据库的拷贝服务器:扩展系统处理读请求的能力: 复制的定义 Redis的复制(replication)功能允许用户根据一个Redis服务器来创建任意多个该服务器的复制品,其中被 ...
- 翻译:Knockout 快速上手 - 2: 安装 knockoutJS
只需要五个简单的步骤,就可以做好使用 Knockout 开发的准备! 第一步 我们需要什么? 最低限度,为了完成后面的教程,你需要如下的准备 Web 浏览器 文本编辑器 你的电脑上大约 2M 的磁盘空 ...