【轉】Hadoop Streaming 使用總結

Hadoop Streaming 是 Hadoop 提供的一個工具, 用戶可以使用它來創建和運行一類特殊的 MapReduce 任務, 這些 MR 任務可以使用任何可執行文件或腳本作爲 mapper 和 reducer。

比如,簡單的 word count 任務可使用 Hadoop Streaming 簡單寫爲:

1
2
3
4
5
6
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
    -input /tmp/wordcount/input \
    -output /tmp/wordcount/output \
    -mapper /bin/cat \
    -reducer /usr/bin/wc
 

工作原理

Hadoop Streaming 會創建一個 MR 任務, 然後將任務提交到集羣上執行,同時監控這個任務的整個執行過程。如果 mapper 和 reducer 都是可執行文件,streaming 程序會使用 PipeMapper 和 PipeReducer 來做一個類似代理的 Mapper 和 Reducer,它們負責啓動實際的 mapper 和 reducer 可執行文件,然後從 HDFS 讀取輸入數據,再一行一行寫入到可執行文件進程的標準輸入,同時讀取可執行文件進程處理完數據後輸出到標準輸出的數據,將其寫出到 Mapper 和 Reducer 真正的輸出中。

以一個沒有 reduce 階段的 Streaming 程序爲例,其 Mapper 簡要運行流程可見下圖:

Hadoop Streaming Mapper 運行流程

Hadoop Streaming Mapper 運行流程

 

PipeMapper 在啓動 mapper.sh 後, 不斷重複 2-7 (一次 map )過程,直到所有數據處理完成。

與 PipeMapper 類似,PipeReducer 會將從 map 端 shuffle 過來數據,一行行的寫到 reducer.sh 進程的標準輸入,然後收集 reducer.sh 進程的標準輸出,最終寫出到 hdfs output。

以上就是是 MapReduce 框架和 streaming mapper/reducer 之間的基本處理流程。所以,用戶在編寫 Streaming 程序的 mapper 和 reducer 時,只需要從不斷 stdin 中一行行讀取數據,處理然後輸出到標準輸出中即可。

同時,用戶也可以使用 java 類作爲 mapper 或者 reducer 。上面的例子與這裏的代碼等價:

1
2
3
4
5
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
    -input /tmp/wordcount/input \
    -output /tmp/wordcount/output \
    -mapper org.apache.hadoop.mapred.lib.IdentityMapper \
    -reducer /usr/bin/wc
 

用戶也可以設定 stream.non.zero.exit.is.failure true  false 來表明 streaming task 的返回值非零時是 Failure 還是 Success。默認情況,streaming task 返回非零時表示失敗。

參數配置

Hadoop Streaming 支持 Streaming 命令參數配置以及 Hadoop 通用的參數配置。 常規命令行語法如下所示。

1
hadoop command [genericOptions] [streamingOptions]
 

注意:確保通用參數放置在 Streaming 的參數配置之前,否則命令將會失敗。 具體可查看後續的示例。

Streaming 參數配置

Streaming 命令參數配置具體如下表所示:

參數 必選 意義
-input directoryname or filename 設置輸入數據路徑,可以是文件或者目錄。可通過重複配置,添加多個輸入路徑
-output directoryname 設置指定輸出數據路徑,必須是目錄。輸出路徑只能有一個
-mapper executable or JavaClassName 設置可執行的 mapper
-reducer executable or JavaClassName 設置可執行的 reducer
-file filename 設置需要同步到計算節點的文件,可以使可執行的 mapper,reducer 或 combiner 文件在計算節點本地可用。可以通過重複配置,同步多個文件
-inputformat JavaClassName 設置 InputFormat,用來將輸入文件讀取成 key/value 對,如果未設置默認使用 TextInputFormat
-outputformat JavaClassName 設置 OutputFormat,用來將輸出的 key/value 對寫出到輸出文件,如果未設置默認使用 TextOutputFormat
-partitioner JavaClassName 設置 Partitioner, 用來根據 key 確定數據應該指派到的 reduce
-combiner streamingCommand or JavaClassName 設置 Combiner,用來在 mapper 端歸併 mapper 的輸出
-cmdenv name=value 設置環境變量,可以在 mapper 或者 reducer 運行時獲取
-inputreader 設置 InputReader 類,用於讀取輸入數據,取代 InputFormat Class
-verbose 設置是否輸出日誌
-lazyOutput 設置是否延遲輸出
-numReduceTasks 設置 reducer 任務數量
-mapdebug 設置 mapper debug 腳本,在 mapper 任務運行失敗時執行
-reducedebug 設置 reducer debug 腳本, reducer 任務運行失敗時執行

通用參數配置

Streaming 任務同時支持 Hadoop 通用的參數配置,主要的參數配置有以下幾個:

參數 必選 意義
-conf configuration_file 指定配置文件
-D property=value 設置參數的值
-fs host:port or local 指定一個 namenode
-files 指定需要拷貝到集羣的文件,多個文件以逗號分隔
-libjars 指定需要添加到任務 classpath 的 jar 文件,多個文件以逗號分隔
-archives 指定需要解壓到計算節點的壓縮文件,多個文件以逗號分隔

參數配置示例

下面我們通過一些示例來展示具體的 Streaming 任務參數配置。

設置 Mapper Reducer

使用可執行文件作爲 mapper 和 reducer

1
2
3
4
5
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -input myInputDir \
  -output myOutputDir \
  -mapper /usr/bin/cat \
  -reducer /usr/bin/wc
 

使用 Java Class 作爲 mapper,指定 InputFormat

1
2
3
4
5
6
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -input myInputDir \
  -output myOutputDir \
  -inputformat org.apache.hadoop.mapred.KeyValueTextInputFormat \
  -mapper org.apache.hadoop.mapred.lib.IdentityMapper \
  -reducer /usr/bin/wc
 

提交任務時打包文件

如上文所述,我們可以指定任意的可執行文件作爲 mapper 或者 reducer。在提交 Hadoop Streaming 任務時, 可執行的 mapper 或者 reducer 執行文件並不必已經存在 Hadoop 集羣的任意一臺機器上。如果不存在,我們只需要在提交任務時的時候使用 -file 參數指定需要的文件,告訴集羣在提交任務時將這些文件打包,這樣 Hadoop 會自動將這些文件打包上傳到 Hdfs,並同步到每個計算節點。

1
2
3
4
5
6
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -input myInputDir \
  -output myOutputDir \
  -mapper wordcount.py \
  -reducer /usr/bin/wc \
  -file wordcount.py
 

同時,你也可以指定一些依賴文件,打包上傳到集羣上,提供給 mapper 或者 reducer 任務使用

1
2
3
4
5
6
7
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -input myInputDir \
  -output myOutputDir \
  -mapper wordcount.py \
  -reducer /usr/bin/wc \
  -file wordcount.py \
  -file dictionary.txt
 

指定任務的其他插件

跟普通的 MR 任務一樣,我們可以指定任務運行時的一些插件

1
2
3
4
-inputformat JavaClassName
-outputformat JavaClassName
-partitioner JavaClassName
-combiner streamingCommand or JavaClassName
 

設置環境變量

我們也可以通過參數設置任務運行時的環境變量,並且可以在 mapper 或者 reducer 運行時獲取環境變量的值。

1
2
3
4
5
6
7
8
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -input myInputDir \
  -output myOutputDir \
  -mapper wordcount.py \
  -reducer /usr/bin/wc \
  -file wordcount.py \
  -cmdenv EXAMPLE_DIR=/home/example/dictionaries/ \
  -cmdenv LOG_LEVEL=debug
 

設置 reducer 數量

通常,我們需要爲任務設置合適的 reducer 數量,默認的 reducer 數量是 1,具體的 reducer 數量應當根據業務需求以及可使用資源等因素來確定。
reducer 數量可以使用 Streaming 配置 -numReduceTasks 10 或者通用參數 -D mapreduce.job.reduces=10 來設置。如下,我們將任務的 reducer 數量設爲 10。

1
2
3
4
5
6
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -D mapreduce.job.reduces=10
  -input myInputDir \
  -output myOutputDir \
  -mapper /usr/bin/cat \
  -reducer /usr/bin/wc
 

對於 map-only 的任務,在 map 結束後直接輸出結果即可,不需要進行 reduce,這時我們需要將 reducer 數量設爲 0。設置 -D mapreduce.job.reduces=0 或者 -reducer=NONE 即可。

依賴大文件或者歸檔文件

很多 Streaming 任務在運行時需要依賴某些特定的文件或者環境,比如某些分詞任務依賴字典文件,或某個 python 實現的機器學習任務依賴指定的 module 。此時,我們就需要將依賴的文件或者歸檔上傳到 HDFS 上, 並使用 -files  -archives 選項指定已上傳的依賴文件或者歸檔的 HDFS 路徑,任務運行時將會將指定的依賴文件和歸檔分發到各個計算節點上,任務運行時即可依賴這些文件進行相應的操作。

注意:-files  -archives 選項都是通用選項,需要放在 Streaming 命令配置前,否則會導致任務啓動失敗

-files 選項指定的依賴文件會在任務啓動之前分發到當前計算節點上。依賴文件分完成後,會在任務的工作目錄裏建個軟鏈指向它。
如下示例,Hadoop 會在任務的當前工作目錄中自動創建名爲 dict.txt 的符號鏈接,指向 dict.txt 的實際複製到的本地路徑。任務直接通過軟鏈引用文件即可。

1
-files hdfs://host:port/tmp/cache/dict.txt
 

用戶也可以自己指定符號鏈接的名稱,如下示例,將建立名爲 dict 的軟鏈。

1
-files hdfs://host:port/tmp/cache/dict.txt#dict
 

對於多個依賴文件,可以用逗號分隔

1
-files hdfs://host:port/tmp/cache/dict.txt,hdfs://host:port/tmp/cache/test.txt
 

-archives 選項指定的歸檔文件會在任務啓動之前分發到當前計算節點上,對於使用某些壓縮的歸檔文件(tar 或 jar)分發到計算節點上後, Hadoop 會自動將其解壓到一個目錄裏,並在任務的工作目錄裏建個軟鏈指向這個目錄。
如下示例,Hadoop 會在任務的當前工作目錄中自動創建名爲 dict.tar.gz 的符號鏈接,指向 dict.tar.gz 解壓到的目錄。

1
-archives hdfs://host:port/tmp/cache/dict.tar.gz
 

用戶也可以自己指定符號鏈接的名稱,如下示例,將建立名爲 mydict 的軟鏈。

1
-archives hdfs://host:port/tmp/cache/dict.tar.gz#mydict
 

指定多個歸檔依賴文件,可以用逗號分隔。

1
-archives hdfs://host:port/tmp/cache/dict.tar.gz,hdfs://host:port/tmp/cache/test.tar.gz
 

對於任務依賴包含許多文件的目錄時,如 python 依賴的某些集羣上不存在的第三方 module, 我們可以先將整個目錄歸檔壓縮後上傳到 HDFS 上,並使用 -archives 指定上傳後的路徑,即可在 python 實現的 mapper 或 reducer 運行時引用 module 進行相關的計算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tar -czvf test_moudle.tar.gz -C test_moudle/ .
hadoop fs -put test_moudle.tar.gz /tmp/cache/test_moudle.tar.gz
# 打包上傳完成後,在依賴未更新時,後續任務啓動時不要重新打包上傳歸檔文件
# 在 mapper.py 或 reducer.py 直接用 ./tmodule 路徑讀取或者引用即可

hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar \
  -archives hdfs://host:port/tmp/cache/test_moudle.tar.gz#tmodule \
  -D mapreduce.job.reduces=1 \
  -D mapreduce.job.name="TestArchives" \
  -input myInputDir \
  -output myOutputDir \
  -mapper 'python mapper.py' \
  -reducer 'python reducer.py'
 

Streaming 任務本地測試

因爲在集羣上對失敗任務進行 debug 比較麻煩一些,所以在提交任務之前,建議先在本地對任務進行簡單的測試,測試通過後再提交到集羣。

簡單測試命令如下:

1
cat inputfile | sh mapper.sh | sort |sh reducer.sh > output
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章