“兵马未动,粮草先行”,要想深入的了解hadoop,我觉得启动或停止hadoop的脚本是必须要先了解的。说到底,hadoop就是一个分布式存储和计算框架,但是这个分布式环境是如何启动,管理的呢,我就带着大家先从脚本入手吧。说实话,hadoop的启动脚本写的真好,里面考虑的地方非常周全(比如说路径中有空格,软连接等)。
1、hadoop脚本简单介绍
hadoop的脚本分布在$HADOOP_HOME下面的bin目录下和conf文件夹下,主要介绍如下:
bin目录下
hadoop hadoop底层核心脚本,所有分布式程序最终都是通过这个脚本启动的。
hadoop-config.sh 基本别的脚本都会内嵌调用这个脚本,这个脚本作用就是解析命令行可选参数(--config :hadoop conf文件夹路径 和--hosts)
hadoop-daemon.sh 启动或停止本机command参数所指定的分布式程序,通过调用hadoop脚本实现。
hadoop-daemons.sh 启动所有机器上的hadoop分布式程序,通过调用slaves.sh实现。
slaves.sh 在所有的机器上运行一组指定的命令(通过ssh无密码登陆),供上层使用。
start-dfs.sh
在本机启动namenode,在slaves机器上启动datanode,在master机器上启动secondarynamenode,通过调用
hadoop-daemon.sh和hadoop-daemons.sh实现。
start-mapred.sh 在本机启动jobtracker,在slaves机器上启动tasktracker,通过调用hadoop-daemon.sh和hadoop-daemons.sh实现。
start-all.sh 启动所有分布式hadoop程序,通过调用start-dfs.sh和start-mapred.sh实现。
start-balancer.sh 启动hadoop分布式环境复杂均衡调度程序,平衡各节点存储和处理能力。
还有几个stop 脚本,就不用详细说了。
conf目录下
hadoop-env.sh 配置hadoop运行时所需要的一些参数变量,比如JAVA_HOME,HADOOP_LOG_DIR,HADOOP_PID_DIR等。
2、脚本的魅力(详细解释)
hadoop的脚本写的真好,不服不行,从中学习到了好多知识。
2.1、hadoop-config.sh
这个脚本比较简单,而且基本其他脚本都内嵌通过“. $bin/hadoop-config.sh”的形式调用此脚本,所以这个脚本就不用在第一行声明解释权,因为这种调用方式类似于把此脚本内容复制到父脚本里在同一个解释器里面运行。
这个脚本主要做三部分内容:
1、软连接解析和绝对路径解析
1. #软连接解析
2. this="$0"
3. while [ -h "$this" ]; do
4. ls=`ls -ld "$this"`
5. link=`expr "$ls" : '.*-> \(.*\)$'`
6. > /dev/null; then
7. this="$link"
8. else
9. this=`dirname "$this"`/"$link"
10. fi
11. done
12.
13. #绝对路径解析
14. # convert relative path to absolute path
15. bin=`dirname "$this"`
16. script=`basename "$this"`
17. bin=`cd "$bin"; pwd`
18. this="$bin/$script"
19.
20. # the root of the Hadoop installation
21. export HADOOP_HOME=`dirname "$this"`/..
2、命令行可选参数--config解析并赋值
1. #check to see if the conf dir is given as an optional argument
2. if [ $# -gt 1 ]
3. then
4. if [ "--config" = "$1" ]
5. then
6. shift
7. confdir=$1
8. shift
9. HADOOP_CONF_DIR=$confdir
10. fi
11. fi
3、命令行可选参数--config解析并赋值
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. HADOOP_SLAVES="${HADOOP_CONF_DIR}/$slavesfile"
11. fi
12. fi
2.2、hadoop
此脚本是hadoop脚本的核心,变量的设置,程序的启动都是通过这个脚本做的。
1、声明使用方法
1. # if no args specified, show usage
2. if [ $# = 0 ]; then
3. echo "Usage: hadoop [--config confdir] COMMAND"
4. echo "where COMMAND is one of:"
5. echo " namenode -format format the DFS filesystem"
6. echo " secondarynamenode run the DFS secondary namenode"
7. echo " namenode run the DFS namenode"
8. echo " datanode run a DFS datanode"
9. echo " dfsadmin run a DFS admin client"
10. echo " mradmin run a Map-Reduce admin client"
11. echo " fsck run a DFS filesystem checking utility"
12. echo " fs run a generic filesystem user client"
13. echo " balancer run a cluster balancing utility"
14. echo " jobtracker run the MapReduce job Tracker node"
15. echo " pipes run a Pipes job"
16. echo " tasktracker run a MapReduce task Tracker node"
17. echo " job manipulate MapReduce jobs"
18. echo " queue get information regarding JobQueues"
19. echo " version print the version"
20. <jar> run a jar file"
21. <srcurl> <desturl> copy file or directories recursively"
22. <src>* <dest> create a hadoop archive"
23. echo " daemonlog get/set the log level for each daemon"
24. echo " or"
25. echo " CLASSNAME run the class named CLASSNAME"
26. echo "Most commands print help when invoked w/o parameters."
27. exit 1
28. fi
2、设置java运行环境
代码简单,就不写出来了,包括JAVA_HOME,JAVA_HEAP_MAX,CLASSPATH,HADOOP_LOG_DIR,HADOOP_POLICYFILE。其中用到了设置IFS-储界定符号的环境变量,默认值是空白字符(换行,制表符或者空格)。
3、根据cmd设置运行时class
1. # figure out which class to run
2. if [ "$COMMAND" = "namenode" ] ; then
3. CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'
4. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"
5. elif [ "$COMMAND" = "secondarynamenode" ] ; then
6. CLASS='org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode'
7. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_SECONDARYNAMENODE_OPTS"
8. elif [ "$COMMAND" = "datanode" ] ; then
9. CLASS='org.apache.hadoop.hdfs.server.datanode.DataNode'
10. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_DATANODE_OPTS"
11. elif [ "$COMMAND" = "fs" ] ; then
12. CLASS=org.apache.hadoop.fs.FsShell
13. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
14. elif [ "$COMMAND" = "dfs" ] ; then
15. CLASS=org.apache.hadoop.fs.FsShell
16. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
17. elif [ "$COMMAND" = "dfsadmin" ] ; then
18. CLASS=org.apache.hadoop.hdfs.tools.DFSAdmin
19. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
20. elif [ "$COMMAND" = "mradmin" ] ; then
21. CLASS=org.apache.hadoop.mapred.tools.MRAdmin
22. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
23. elif [ "$COMMAND" = "fsck" ] ; then
24. CLASS=org.apache.hadoop.hdfs.tools.DFSck
25. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
26. elif [ "$COMMAND" = "balancer" ] ; then
27. CLASS=org.apache.hadoop.hdfs.server.balancer.Balancer
28. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_BALANCER_OPTS"
29. elif [ "$COMMAND" = "jobtracker" ] ; then
30. CLASS=org.apache.hadoop.mapred.JobTracker
31. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_JOBTRACKER_OPTS"
32. elif [ "$COMMAND" = "tasktracker" ] ; then
33. CLASS=org.apache.hadoop.mapred.TaskTracker
34. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_TASKTRACKER_OPTS"
35. elif [ "$COMMAND" = "job" ] ; then
36. CLASS=org.apache.hadoop.mapred.JobClient
37. elif [ "$COMMAND" = "queue" ] ; then
38. CLASS=org.apache.hadoop.mapred.JobQueueClient
39. elif [ "$COMMAND" = "pipes" ] ; then
40. CLASS=org.apache.hadoop.mapred.pipes.Submitter
41. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
42. elif [ "$COMMAND" = "version" ] ; then
43. CLASS=org.apache.hadoop.util.VersionInfo
44. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
45. elif [ "$COMMAND" = "jar" ] ; then
46. CLASS=org.apache.hadoop.util.RunJar
47. elif [ "$COMMAND" = "distcp" ] ; then
48. CLASS=org.apache.hadoop.tools.DistCp
49. CLASSPATH=${CLASSPATH}:${TOOL_PATH}
50. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
51. elif [ "$COMMAND" = "daemonlog" ] ; then
52. CLASS=org.apache.hadoop.log.LogLevel
53. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
54. elif [ "$COMMAND" = "archive" ] ; then
55. CLASS=org.apache.hadoop.tools.HadoopArchives
56. CLASSPATH=${CLASSPATH}:${TOOL_PATH}
57. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
58. elif [ "$COMMAND" = "sampler" ] ; then
59. CLASS=org.apache.hadoop.mapred.lib.InputSampler
60. HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
61. else
62. CLASS=$COMMAND
63. fi
4、设置本地库
1. # setup 'java.library.path' for native-hadoop code if necessary
2. JAVA_LIBRARY_PATH=''
3. if [ -d "${HADOOP_HOME}/build/native" -o -d "${HADOOP_HOME}/lib/native" ]; then
4. #通过运行一个java 类来决定当前平台,挺有意思
5. JAVA_PLATFORM=`CLASSPATH=${CLASSPATH} ${JAVA} -Xmx32m org.apache.hadoop.util.PlatformName | sed -e "s/ /_/g"`
6.
7. if [ -d "$HADOOP_HOME/build/native" ]; then
8. JAVA_LIBRARY_PATH=${HADOOP_HOME}/build/native/${JAVA_PLATFORM}/lib
9. fi
10.
11. if [ -d "${HADOOP_HOME}/lib/native" ]; then
12. if [ "x$JAVA_LIBRARY_PATH" != "x" ]; then
13. JAVA_LIBRARY_PATH=${JAVA_LIBRARY_PATH}:${HADOOP_HOME}/lib/native/${JAVA_PLATFORM}
14. else
15. JAVA_LIBRARY_PATH=${HADOOP_HOME}/lib/native/${JAVA_PLATFORM}
16. fi
17. fi
18. fi
5、运行分布式程序
1. # run it
2. xec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"
2.3、hadoop-daemon.sh
启动或停止本机command参数所指定的分布式程序,通过调用hadoop脚本实现,其实也挺简单的。
1、声明使用方法
1. usage="Usage: hadoop-daemon.sh [--config <conf-dir>] [--hosts hostlistfile] (start|stop) <hadoop-command> <args...>"
2.
3. # if no args specified, show usage
4. if [ $# -le 1 ]; then
5. echo $usage
6. exit 1
7. fi
2、设置环境变量
首先内嵌运行hadoop-env.sh脚本,然后设置HADOOP_PID_DIR等环境变量。
3、启动或停止程序
1. case $startStop in
2.
3. (start)
4.
5. mkdir -p "$HADOOP_PID_DIR"
6.
7. if [ -f $pid ]; then
8. #如果程序已经启动的话,就停止,并退出。
9. > /dev/null 2>&1; then
10. echo $command running as process `cat $pid`. Stop it first.
11. exit 1
12. fi
13. fi
14.
15. if [ "$HADOOP_MASTER" != "" ]; then
16. echo rsync from $HADOOP_MASTER
17. --exclude=.svn --exclude='logs/*' --exclude='contrib/hod/logs/*' $HADOOP_MASTER/ "$HADOOP_HOME"
18. fi
19. # rotate 当前已经存在的log
20. hadoop_rotate_log $log
21. echo starting $command, logging to $log
22. cd "$HADOOP_HOME"
23. #通过nohup 和bin/hadoop脚本启动相关程序
24. > "$log" 2>&1 < /dev/null &
25. #获取新启动的进程pid并写入到pid文件中
26. > $pid
27. sleep 1; head "$log"
28. ;;
29.
30. (stop)
31.
32. if [ -f $pid ]; then
33. > /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. esac
2.4、slaves.sh
在所有的机器上运行一组指定的命令(通过ssh无密码登陆),供上层使用。
1、声明使用方法
1. usage="Usage: slaves.sh [--config confdir] command..."
2.
3. # if no args specified, show usage
4. if [ $# -le 0 ]; then
5. echo $usage
6. exit 1
7. fi
2、设置远程主机列表
1. # If the slaves file is specified in the command line,
2. # then it takes precedence over the definition in
3. # hadoop-env.sh. Save it here.
4. HOSTLIST=$HADOOP_SLAVES
5.
6. if [ -f "${HADOOP_CONF_DIR}/hadoop-env.sh" ]; then
7. . "${HADOOP_CONF_DIR}/hadoop-env.sh"
8. fi
9.
10. if [ "$HOSTLIST" = "" ]; then
11. if [ "$HADOOP_SLAVES" = "" ]; then
12. HOSTLIST="${HADOOP_CONF_DIR}/slaves"
13. else
14. HOSTLIST="${HADOOP_SLAVES}"
15. fi
16. fi
3、分别在远程主机执行相关命令
1. #挺重要,里面技术含量也挺高,对远程主机文件进行去除特殊字符和删除空行;对命令行进行空格替换,并通过ssh在目标主机执行命令;最后等待命令在所有目标主机执行完后,退出。
2. for slave in `cat "$HOSTLIST"|sed "s/#.*$//;/^$/d"`; do
3. ssh $HADOOP_SSH_OPTS $slave $"${@// /\\ }" \
4. >&1 | sed "s/^/$slave: /" &
5. if [ "$HADOOP_SLAVE_SLEEP" != "" ]; then
6. sleep $HADOOP_SLAVE_SLEEP
7. fi
8. done
9.
10. wait
2.5、hadoop-daemons.sh
启动远程机器上的hadoop分布式程序,通过调用slaves.sh实现。
1、声明使用方法
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
2、在远程主机调用命令
1. #通过salves.sh来实现
2. exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_HOME" \; "$bin/hadoop-daemon.sh" --config $HADOOP_CONF_DIR "$@"
2.6、start-dfs.sh
在本机(调用此脚本的主机)启动namenode,在slaves机器上启动datanode,在master机器上启动secondarynamenode,通过调用hadoop-daemon.sh和hadoop-daemons.sh实现。
1、声明使用方式
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]"
2、启动程序
1. # start dfs daemons
2. # start namenode after datanodes, to minimize time namenode is up w/o data
3. # note: datanodes will log connection errors until namenode starts
4. #在本机(调用此脚本的主机)启动namenode
5. "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start namenode $nameStartOpt
6. #在slaves机器上启动datanode
7. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start datanode $dataStartOpt
8. #在master机器上启动secondarynamenode
9. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR --hosts masters start secondarynamenode
2.7、start-mapred.sh
在本机(调用此脚本的主机)启动jobtracker,在slaves机器上启动tasktracker,通过调用hadoop-daemon.sh和hadoop-daemons.sh实现。
1. # start mapred daemons
2. # start jobtracker first to minimize connection errors at startup
3. #在本机(调用此脚本的主机)启动jobtracker
4. "$bin"/hadoop-daemon.sh --config $HADOOP_CONF_DIR start jobtracker
5. #在master机器上启动tasktracker
6. "$bin"/hadoop-daemons.sh --config $HADOOP_CONF_DIR start tasktracker
其他的脚本就都已经非常简单了,不用再详细说明了,只要看下,大致都能看懂。
对了,最后再说下hadoop的脚本里面用的shell解释器的声明吧。
1. #!/usr/bin/env bash
作用就是适应各种linux操作系统,能够找到 bash shell来解释执行本脚本,也挺有用的。