Hadoop作業提交分析(一)

bin/hadoop jar xxx.jar mainclass args
……

  這樣的命令,各位玩Hadoop的估計已經調用過NN次了,每次寫好一個Project或對Project做修改後,都必須打個Jar包,然後再用上面的命令提交到Hadoop Cluster上去運行,在開發階段那是極其繁瑣的。程序員是“最懶”的,既然麻煩肯定是要想些法子減少無謂的鍵盤敲擊,順帶延長鍵盤壽命。比如有的人就寫了些Shell腳本來自動編譯、打包,然後提交到Hadoop。但還是稍顯麻煩,目前比較方便的方法就是用Hadoop eclipse plugin,可以瀏覽管理HDFS,自動創建MR程序的模板文件,最爽的就是直接Run on hadoop了,但版本有點跟不上Hadoop的主版本了,目前的MR模板還是0.19的。還有一款叫Hadoop Studio的軟件,看上去貌似是蠻強大,但是沒試過,這裏不做評論。那麼它們是怎麼做到不用上面那個命令來提交作業的呢?不知道?沒關係,開源的嘛,不懂得就直接看源碼分析,這就是開源軟件的最大利處。

       我們首先從bin/hadoop這個Shell腳本開始分析,看這個腳本內部到底做了什麼,如何來提交Hadoop作業的。

       因爲是Java程序,這個腳本最終都是要調用Java來運行的,所以這個腳本最重要的就是添加一些前置參數,如CLASSPATH等。所以,我們直接跳到這個腳本的最後一行,看它到底添加了那些參數,然後再逐個分析(本文忽略了腳本中配置環境參數載入、Java查找、cygwin處理等的分析)。

# run it
exec
"$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"

  從上面這行命令我們可以看到這個腳本最終添加了如下幾個重要參數:JAVA_HEAP_MAX、HADOOP_OPTS、CLASSPATH、CLASS。下面我們來一個個的分析(本文基於Cloudera Hadoop 0.20.1+152分析)。

  首先是JAVA_HEAP_MAX,這個就比較簡單了,主要涉及代碼如下:

複製代碼
JAVA_HEAP_MAX=-Xmx1000m
# check envvars which might override default args
if [ "$HADOOP_HEAPSIZE" != "" ]; then
#echo "run with heapsize $HADOOP_HEAPSIZE"
JAVA_HEAP_MAX
="-Xmx""$HADOOP_HEAPSIZE""m"
#echo $JAVA_HEAP_MAX
fi
複製代碼

  首先賦予默認值-Xmx1000m,然後檢查hadoop-env.sh中是否設置並導出了HADOOP_HEAPSIZE,如果有的話,就使用該值覆蓋,得到最後的JAVA_HEAP_MAX。

  接着是分析CLASSPATH,這是這個腳本的重點之一。這部分主要就是添加了相應依賴庫和配置文件到CLASSPATH。

複製代碼
# 首先用Hadoop的配置文件目錄初始化CLASSPATH
CLASSPATH
="${HADOOP_CONF_DIR}"
……
# 下面是針對於Hadoop發行版,添加Hadoop核心Jar包和webapps到CLASSPATH
if [ -d "$HADOOP_HOME/webapps" ]; then
CLASSPATH
=${CLASSPATH}:$HADOOP_HOME
fi
for f in $HADOOP_HOME/hadoop-*-core.jar; do
CLASSPATH
=${CLASSPATH}:$f;
done
# 添加libs裏的Jar包
for f in $HADOOP_HOME/lib/*.jar; do
CLASSPATH
=${CLASSPATH}:$f;
Done
for f in $HADOOP_HOME/lib/jsp-2.1/*.jar; do
CLASSPATH
=${CLASSPATH}:$f;
done
# 下面的TOOL_PATH只在命令爲“archive”時才添加到CLASSPATH
for f in $HADOOP_HOME/hadoop-*-tools.jar; do
TOOL_PATH
=${TOOL_PATH}:$f;
done
for f in $HADOOP_HOME/build/hadoop-*-tools.jar; do
TOOL_PATH
=${TOOL_PATH}:$f;
done
# 最後添加用戶的自定義Hadoop Classpath
if [ "$HADOOP_CLASSPATH" != "" ]; then
CLASSPATH
=${CLASSPATH}:${HADOOP_CLASSPATH}
fi
複製代碼

  上面只分析一部分,由於代碼比較長,針對開發者部分的CLASSPATH添加沒有列出來。

  下面是這個腳本的重點、實體之處:CLASS分析。Shell腳本會根據你輸入的命令參數來設置CLASS和HADOOP_OPTS,其中CLASS所指向的類纔是最終真正執行你的命令的實體。

複製代碼
# figure out which class to run
if [ "$COMMAND" = "namenode" ] ; then
CLASS
='org.apache.hadoop.hdfs.server.namenode.NameNode'
HADOOP_OPTS
="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"
……
elif [
"$COMMAND" = "fs" ] ; then
CLASS
=org.apache.hadoop.fs.FsShell
HADOOP_OPTS
="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
……
elif [
"$COMMAND" = "jar" ] ; then
CLASS
=org.apache.hadoop.util.RunJar
……
elif [
"$COMMAND" = "archive" ] ; then
CLASS
=org.apache.hadoop.tools.HadoopArchives
CLASSPATH
=${CLASSPATH}:${TOOL_PATH}
HADOOP_OPTS
="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
……
else
CLASS
=$COMMAND
fi
複製代碼

  這裏我們要關心的就是"$COMMAND" = "jar"時對應的類org.apache.hadoop.util.RunJar,這個類等下我們繼續分析,這是我們通向最終目標的下一個路口。

  腳本在最後還設置了hadoop.log.dir、hadoop.log.file等HADOOP_OPTS。接着,就利用exec命令帶上剛纔的參數提交任務了。

  通過對上面的分析,我們知道了,如果想取代這個腳本,那就必須至少把Hadoop依賴的庫和配置文件目錄給加到CLASSPATH中(JAVA_HEAP_MAX和HADOOP_OPTS不是必須的),然後調用org.apache.hadoop.util.RunJar類來提交Jar到Hadoop。

 

  PS:對Bash Shell不熟的可以先看看這個http://learn.akae.cn/media/ch31s05.html

 

  To be continued...

----------------------------------------------------------------------------------------------------------

轉載原文地址爲:http://www.cnblogs.com/spork/archive/2010/04/07/1706162.html

發佈了86 篇原創文章 · 獲贊 91 · 訪問量 48萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章