您好,登錄后才能下訂單哦!
1 基本概述
Hadoop的命令位于${HADOOP_HOME}/bin、${HADOOP_HOME}/sbin、${HADOOP_HOME}/libexec下面。包含了Linux的shell腳本和windows的批處理文件。本文主要解析linux下的shell腳本。
2 腳本詳解
2.1 start-all.sh
要啟動Hadoop的各節點和其他服務,這是一個繞不開的啟動腳本,該腳本位于${HADOOP_HOME}/sbin下。不過在Hadoop的2.x版本中,Hadoop官方已經宣布被棄用了。接下來,就詳細地分析一下該腳本是如何工作的:
1、首先腳本開頭有一段注釋:# Start all hadoop daemons. Run this on master node.中文意思是:啟動所有的進程(也就是各節點),在管理節點(也就是namenode-名稱節點)上運行該腳本。
2、如果是2.x版本會有echo "This script is Deprecated. Instead usestart-dfs.sh and start-yarn.sh"的提示,意思該腳本已經過時,該腳本已經被start-dfs.sh和 start-yarn.sh替代使用。
3、bin=`dirname"${BASH_SOURCE-$0}"`,提取start-all.sh的所在的絕對路徑。
4、bin=`cd"$bin"; pwd`,切換到start-all.sh的所在目錄下,并將路徑賦值給bin。
5、DEFAULT_LIBEXEC_DIR="$bin"/../libexec,獲取${HADOOP_HOME}/libexec的絕對路徑以備后用。
6、HADOOP_LIBEXEC_DIR=${HADOOP_LIBEXEC_DIR:-$DEFAULT_LIBEXEC_DIR},為HADOOP_LIBEXEC_DIR變量三元賦值。如果HADOOP_LIBEXEC_DIR為空或者環境變量沒有配置,就賦值默認的絕對路徑,為下一步執行該目錄下面的腳本做準備。
7、.$HADOOP_LIBEXEC_DIR/hadoop-config.sh。執行${HADOOP_HOME}/libexec/hadoop-config.sh腳本。為后面執行啟動各節點和啟動YARN做預處理。
8、執行節點啟動腳本
if [ -f"${HADOOP_HDFS_HOME}"/sbin/start-dfs.sh ]; then
"${HADOOP_HDFS_HOME}"/sbin/start-dfs.sh--config $HADOOP_CONF_DIR
fi
這段腳本的意圖是:如果${HADOOP_HDFS_HOME}/sbin/start-dfs.sh為文件,則聯合--config參數及其后面的參數值執行start-dfs.sh。start-dfs.sh后面做詳細分析。
另外看注釋:# start hdfsdaemons if hdfs is present,中文意思是:啟動hdfs進程。
9、執行YRAN調度服務
if [ -f"${HADOOP_YARN_HOME}"/sbin/start-yarn.sh ]; then
"${HADOOP_YARN_HOME}"/sbin/start-yarn.sh --config$HADOOP_CONF_DIR
fi
這段腳本的意圖是:如果${HADOOP_HDFS_HOME}/sbin/start-yarn.sh為文件,則聯合--config參數及其后面的參數值執行start-yarn.sh。start-yarn.sh后面做詳細分析。
另外看注釋:# start yarndaemons if yarn is present,中文意思是:啟動yarn進程。
備注:${HADOOP_HDFS_HOME}已經在hadoop-config.sh做了預處理。hadoop-config.sh后面做詳細的分析。
2.2 hadoop-config.sh
該腳本位于${HADOOP_HOME}/libexec下。該腳本是在啟動節點和其他服務之前必須要執行的一個腳本。它的主要目的使用啟動Hadoop之前做一些環境變量預處理。接下來,就詳細地分析一下該腳本是如何工作的:
1、文件最前面的注釋:Resolvelinks ($0 may be a softlink) and convert a relative path to an absolute path。中文意思是:解析路徑并將一些相對路徑轉成絕對路徑。
2、執行hadoop-layout.sh腳本
this="${BASH_SOURCE-$0}"
common_bin=$(cd-P -- "$(dirname -- "$this")" && pwd -P)
script="$(basename-- "$this")"
this="$common_bin/$script"
[ -f"$common_bin/hadoop-layout.sh" ] && ."$common_bin/hadoop-layout.sh"
這段腳本的意圖就是找出hadoop-layout.sh并執行,如果沒有找出來就不執行。同時有些變量為后面的程序執行做準備。
3、準備HDFS、YRAN、Mapreduce的jar包路徑并設置路徑
HADOOP_COMMON_DIR=${HADOOP_COMMON_DIR:-"share/hadoop/common"}
HADOOP_COMMON_LIB_JARS_DIR=${HADOOP_COMMON_LIB_JARS_DIR:-"share/hadoop/common/lib"}
HADOOP_COMMON_LIB_NATIVE_DIR=${HADOOP_COMMON_LIB_NATIVE_DIR:-"lib/native"}
HDFS_DIR=${HDFS_DIR:-"share/hadoop/hdfs"}
HDFS_LIB_JARS_DIR=${HDFS_LIB_JARS_DIR:-"share/hadoop/hdfs/lib"}
YARN_DIR=${YARN_DIR:-"share/hadoop/yarn"}
YARN_LIB_JARS_DIR=${YARN_LIB_JARS_DIR:-"share/hadoop/yarn/lib"}
MAPRED_DIR=${MAPRED_DIR:-"share/hadoop/mapreduce"}
MAPRED_LIB_JARS_DIR=${MAPRED_LIB_JARS_DIR:-"share/hadoop/mapreduce/lib"}
4、設置${Hadoop_Home}的根目錄的環境變量
HADOOP_DEFAULT_PREFIX=$(cd -P --"$common_bin"/.. && pwd -P)
HADOOP_PREFIX=${HADOOP_PREFIX:-$HADOOP_DEFAULT_PREFIX}
export HADOOP_PREFIX
5、判斷輸出參數
if [ $# -gt 1 ]
then
if ["--config" = "$1" ]
then
shift
confdir=$1
if [ ! -d "$confdir" ]; then
echo "Error: Cannot find configuration directory: $confdir"
exit 1
fi
shift
HADOOP_CONF_DIR=$confdir
fi
fi
這段代碼參數的意思:$#是表示輸入的參數個數,如果個數大于1,則判斷—config后面的參數是否是一個目錄。如果不是,則退出執行,如果是將傳入的參數賦值給HADOOP_CONF_DIR變量,即將HADOOP_CONF_DIR變量定位到hadoop的配置目錄。
6、設置hadoop的日志級別
if [ $# -gt 1 ]
then
if [ "--loglevel" = "$1"]
then
shift
HADOOP_LOGLEVEL=$1
shift
fi
fi
HADOOP_LOGLEVEL="${HADOOP_LOGLEVEL:-INFO}"
這段代碼的意思是:如果沒有傳入日志參數,則默認為INFO級別。
7、設置HADOOP_CONF_DIR配置的環境變量,也是啟動Hadoop的工作目錄(--config后面的參數值)
if [ -e"${HADOOP_PREFIX}/conf/hadoop-env.sh" ]; then
DEFAULT_CONF_DIR="conf"
else
DEFAULT_CONF_DIR="etc/hadoop"
fi
exportHADOOP_CONF_DIR="${HADOOP_CONF_DIR:-$HADOOP_PREFIX/$DEFAULT_CONF_DIR}"
這段的代碼的意圖是:如果參數值存在,輸出傳入的參數值;如果不存在,使用默認的目錄,一般位于${HADOOP_HOME}/etc/Hadoop.
8、設置部署各個節點hostname配置的環境變量
if [ $# -gt 1 ]
then
if [ "--hosts" = "$1" ]
then
shift
exportHADOOP_SLAVES="${HADOOP_CONF_DIR}/$1"
shift
elif [ "--hostnames" ="$1" ]
then
shift
export HADOOP_SLAVE_NAMES=$1
shift
fi
fi
這段代碼:讀取${HADOOP_HOME}/${HADOOP_CONF_DIR}/slaves文件里面的主機配置列表并輸出HADOOP_SLAVES或者HADOOP_SLAVE_NAMES環境變量。
9、設置hadoop運行的其他環境變量
類似于上面:如果在操作系統的設置過環境變量,則直接使用。如果沒有設置,則設置成默認的環境變量。這些環境變量有:JAVA_HOME、CLASSPATH、JVM啟動參數、JAVA_LIBRARY_PATH、MALLOC_ARENA_MAX等,這里不再一一贅述。如果有不懂的地方,自行查詢java的相關環境變量配置資料
同時還設置了以下的環境變量:HADOOP_HOME、HADOOP_OPTS、HADOOP_COMMON_HOME、TOOL_PATH、HADOOP_HDFS_HOME、LD_LIBRARY_PATH、HADOOP_YARN_HOME、HADOOP_MAPRED_HOME。這些環境變量的設置都引用了前面的變量,這里也不再一一贅述。
2.3 start-hdfs.sh
該腳本位于${HADOOP_HOME}/sbin下。該腳本是啟動集群各節點(包括名稱主節點、各個名稱從節點、各個數據節點)的一個腳本。接下來,就詳細地分析一下該腳本是如何工作的:
1、文件最前面的注釋:Starthadoop dfs daemons。中文意思是:啟動dfs的各個進程。
2、提示信息變量:usage="Usage:start-dfs.sh [-upgrade|-rollback] [other options such as -clusterId]"。提示在執行這個腳本的時候需要主要哪些東西的一個提示信息。
3、執行預處理腳本,這個腳本在前面已經分析過了,不再贅述。
bin=`dirname"${BASH_SOURCE-$0}"`
bin=`cd "$bin"; pwd`
DEFAULT_LIBEXEC_DIR="$bin"/../libexec
HADOOP_LIBEXEC_DIR=${HADOOP_LIBEXEC_DIR:-$DEFAULT_LIBEXEC_DIR}
. $HADOOP_LIBEXEC_DIR/hdfs-config.sh
則也就是不推薦使用的start-all.sh這個腳本的原因所在。
4、根據傳入參數進行判斷進行相應的變量設置
if [[ $# -ge 1]]; then
startOpt="$1"
shift
case "$startOpt" in
-upgrade)
nameStartOpt="$startOpt"
;;
-rollback)
dataStartOpt="$startOpt"
;;
*)
echo $usage
exit 1
;;
esac
fi
這段代碼的意思是:如果參數值的個數大于等于1的時候,如果參數是upgrade,則設置nameStartOpt變量以備后用;如果是rollback,則設置dataStartOpt變量以備后用。
5、添加名稱節點可能參數值
nameStartOpt="$nameStartOpt$@"
6、啟動管理(主)名稱節點
NAMENODES=$($HADOOP_PREFIX/bin/hdfsgetconf -namenodes)
echo"Starting namenodes on [$NAMENODES]"
"$HADOOP_PREFIX/sbin/hadoop-daemons.sh"\
--config"$HADOOP_CONF_DIR" \
--hostnames"$NAMENODES" \
--script"$bin/hdfs" start namenode $nameStartOpt
這段的意思是:將config、hostnames、script的參數值傳給hadoop-daemons.sh執行,啟動名稱主節點。實際上是通過hdfs命令啟動的。
$($HADOOP_PREFIX/bin/hdfs getconf -namenodes)是在提取主名稱節點的主機名。
--script "$bin/hdfs" startnamenode $nameStartOpt實際啟動名稱節點。
hadoop-daemons.sh腳本后面在做詳細分析。
7、啟動數據節點
if [ -n"$HADOOP_SECURE_DN_USER" ]; then
echo \
"Attempting to start secure cluster,skipping datanodes. " \
"Run start-secure-dns.sh as root tocomplete startup."
else
"$HADOOP_PREFIX/sbin/hadoop-daemons.sh"\
--config "$HADOOP_CONF_DIR" \
--script "$bin/hdfs" startdatanode $dataStartOpt
fi
這段的意思是:將config、script的參數值傳給hadoop-daemons.sh執行,啟動數據節點節點。實際上也是通過hdfs命令啟動的。
if [ -n "$HADOOP_SECURE_DN_USER"]; then這段代碼可以忽略,基本不用。
--script "$bin/hdfs" startdatanode $dataStartOpt實際啟動名稱節點。
8、啟動從名稱節點
SECONDARY_NAMENODES=$($HADOOP_PREFIX/bin/hdfsgetconf -secondarynamenodes 2>/dev/null)
if [ -n"$SECONDARY_NAMENODES" ]; then
echo "Starting secondary namenodes[$SECONDARY_NAMENODES]"
"$HADOOP_PREFIX/sbin/hadoop-daemons.sh"\
--config "$HADOOP_CONF_DIR" \
--hostnames"$SECONDARY_NAMENODES" \
--script "$bin/hdfs" startsecondarynamenode
Fi
這段的意思是:將config、hostnames、script的參數值傳給hadoop-daemons.sh執行,啟動名稱主節點。實際上是通過hdfs命令啟動的。
SECONDARY_NAMENODES=$($HADOOP_PREFIX/bin/hdfsgetconf -secondarynamenodes 2>/dev/null),是在提取從名稱節點的主機名。
--script "$bin/hdfs" start namenode secondarynamenode實際啟動名稱節點。
9、后面的執行
后面的執行過程,后面有時間一一補充。
2.4 hadoop-daemons.sh
該腳本位于${HADOOP_HOME}/sbin下。該腳本是具體執行啟動集群各節點(包括名稱主節點、各個名稱從節點、各個數據節點)的一個腳本。接下來,就詳細地分析一下該腳本是如何工作的:
1、其它的代碼可以不做重點關注
2、exec"$bin/slaves.sh" --config $HADOOP_CONF_DIR cd"$HADOOP_PREFIX" \; "$bin/hadoop-daemon.sh" --config$HADOOP_CONF_DIR "$@"
拆解這段代碼:
A、先執行slaves.sh腳本,這個腳本是根據slaves的主機列表迭代執行hadoop-daemon.sh腳本。
B、然后將所有參數傳入并執行hadoop-daemon.sh腳本。
2.5 hadoop-daemon.sh
該腳本位于${HADOOP_HOME}/sbin下。該腳本是具體執行啟動集群各節點(包括名稱主節點、各個名稱從節點、各個數據節點)的一個腳本。接下來,就詳細地分析一下該腳本是如何工作的:
1、先調用hadoop-config.sh腳本,不再贅述。
2、提取hadoop命令并設置變量:
hadoopScript="$HADOOP_PREFIX"/bin/Hadoop
3、提取命令(或是啟動命令,或是停止命令),提取節點(或者名稱節點,或是數據節點)
hadoopScript="$HADOOP_PREFIX"/bin/hadoop
if[ "--script" = "$1" ]
then
shift
hadoopScript=$1
shift
fi
startStop=$1
shift
command=$1
shift
4、輸出日志相關
hadoop_rotate_log()
{
log=$1;
num=5;
if [ -n "$2" ]; then
num=$2
fi
if [ -f "$log" ]; then # rotatelogs
while [ $num -gt 1 ]; do
prev=`expr $num - 1`
[ -f "$log.$prev" ] && mv "$log.$prev""$log.$num"
num=$prev
done
mv "$log" "$log.$num";
fi
}
5、執行環境變量設置腳本
if[ -f "${HADOOP_CONF_DIR}/hadoop-env.sh" ]; then
."${HADOOP_CONF_DIR}/hadoop-env.sh"
fi
6、根據啟動節點的不同重新設置不同的變量值
#Determine if we're starting a secure datanode, and if so, redefine appropriatevariables
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
exportHADOOP_IDENT_STRING=$HADOOP_SECURE_DN_USER
starting_secure_dn="true"
fi
#Determineif we're starting a privileged NFS, if so, redefine the appropriate variables
if[ "$command" == "nfs3" ] && [ "$EUID" -eq0 ] && [ -n "$HADOOP_PRIVILEGED_NFS_USER" ]; then
exportHADOOP_PID_DIR=$HADOOP_PRIVILEGED_NFS_PID_DIR
exportHADOOP_LOG_DIR=$HADOOP_PRIVILEGED_NFS_LOG_DIR
exportHADOOP_IDENT_STRING=$HADOOP_PRIVILEGED_NFS_USER
starting_privileged_nfs="true"
fi
7、中間的都是輸出日志和設置其他臨時變量和環境變量,不做重點介紹,請自行參考腳本
8、啟動或者停止節點
case$startStop in
(start)
[ -w "$HADOOP_PID_DIR" ] || mkdir -p "$HADOOP_PID_DIR"
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
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_PREFIX"
fi
hadoop_rotate_log $log
echo starting $command, logging to $log
cd "$HADOOP_PREFIX"
case $command in
namenode|secondarynamenode|datanode|journalnode|dfs|dfsadmin|fsck|balancer|zkfc)
if [ -z "$HADOOP_HDFS_HOME"]; then
hdfsScript="$HADOOP_PREFIX"/bin/hdfs
else
hdfsScript="$HADOOP_HDFS_HOME"/bin/hdfs
fi
nohup nice -n $HADOOP_NICENESS$hdfsScript --config $HADOOP_CONF_DIR $command "$@" >"$log" 2>&1 < /dev/null &
;;
(*)
nohup nice -n $HADOOP_NICENESS$hadoopScript --config $HADOOP_CONF_DIR $command "$@" >"$log" 2>&1 < /dev/null &
;;
esac
echo $! > $pid
sleep 1
head "$log"
# capture the ulimit output
if [ "true" ="$starting_secure_dn" ]; then
echo "ulimit -a for secure datanodeuser $HADOOP_SECURE_DN_USER" >> $log
# capture the ulimit info for theappropriate user
su --shell=/bin/bash$HADOOP_SECURE_DN_USER -c 'ulimit -a' >> $log 2>&1
elif [ "true" ="$starting_privileged_nfs" ]; then
echo "ulimit -a for privileged nfsuser $HADOOP_PRIVILEGED_NFS_USER" >> $log
su --shell=/bin/bash $HADOOP_PRIVILEGED_NFS_USER-c 'ulimit -a' >> $log 2>&1
else
echo "ulimit -a for user $USER">> $log
ulimit -a >> $log 2>&1
fi
sleep 3;
if ! ps -p $! > /dev/null ; then
exit 1
fi
;;
(stop)
if [ -f $pid ]; then
TARGET_PID=`cat $pid`
if kill -0 $TARGET_PID > /dev/null2>&1; then
echo stopping $command
kill $TARGET_PID
sleep $HADOOP_STOP_TIMEOUT
if kill -0 $TARGET_PID > /dev/null2>&1; then
echo "$command did not stopgracefully after $HADOOP_STOP_TIMEOUT seconds: killing with kill -9"
kill -9 $TARGET_PID
fi
else
echo no $command to stop
fi
rm -f $pid
else
echo no $command to stop
fi
;;
(*)
echo$usage
exit 1
;;
esac
這是一個分支執行流程,分為啟動節點和停止節點:
A、啟動節點分支:在該分支下,首先判斷節點主機上的PID(其實就是默認設置的端口)是否被占用,如果被占用則停止啟動。如果沒有被占用,則開始打印日志,也是我們在控制臺上看到的日志(echo starting $command, logging to $log)。表明開始啟動節點上的hadoop進程,然后根據$command變量判斷啟動哪個節點,最后將所有的參數傳入hdfs命令啟動節點,至此,該節點就啟動起來了。
B、停止節點分支:在該分支下,首先判斷節點主機上的PID(其實就是默認設置的端口)是否被占用,如果被占用則殺掉進程,如果沒有被殺掉,則使用kill-9強制殺掉。如果PID沒有被占用,則會打印提示信息:“沒有XX節點需要停止”, 至此,該節點就停止服務了。
2.6 hdfs
該腳本首先判斷是否有參數傳入或者參數是否正確,如果沒有參數或者參數錯誤,就會提示用戶需要傳遞參數或者傳遞正確的參數。
然后根據參數值判斷后調用jdk(JAVA_HOME)下相應的腳本,最后啟動相應的java進程。
總而言之,這個腳本才是啟動hadoop的最終歸宿,如果能掌握hadoop里面的所有入口函數,也可以認為這個腳本也不是最終歸宿,因為這個腳本的最終目的就是通過調用jdk下面的java命令啟動Hadoop的必要入口函數,也就是main方法,最終達到啟動整個Hadoop集群的目的。
2.7 start-yarn.sh
該腳本的執行流程與start-hdfs的執行流程類似,請自行參考該shell腳本,這里不再贅述。
2.8 yarn-daemons.sh
該腳本的執行流程與hadoop-daemons.sh的執行流程類似,請自行參考該shell腳本,這里不再贅述。
2.9 yarn-daemon.sh
該腳本的執行流程與hadoop-daemon.sh的執行流程類似,請自行參考該shell腳本,這里不再贅述。
2.10 各停止腳本
從上面hadoop-daemon.sh可以看出,停止各節點的服務,無外乎也就是先提取相應的環境變量,然后殺掉相應的進程,將占用端口釋放出來,沒什么大書特書的。如有興趣,可以自行研究停止腳本,這里不再做詳細分析。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。