Streaming簡介
Streaming框架允許任何程序語言實現的程序在Hadoop MapReduce中使用,方便已有程序向Hadoop平臺移植。因此可以說對於hadoop的擴展性意義重大,今天簡單說一下。
Streaming的原理是用Java實現一個包裝用戶程序的MapReduce程序,該程序負責調用MapReduce Java接口獲取key/value對輸入,創建一個新的進程啓動包裝的用戶程序,將數據通過管道傳遞給包裝的用戶程序處理,然後調用MapReduce Java接口將用戶程序的輸出切分成key/value對輸出。
Streaming優點
1 開發效率高,便於移植
只要按照標準輸入輸出格式進行編程,就可以滿足hadoop要求。因此單機程序稍加改動就可以在集羣上進行使用。 同樣便於測試
只要按照 cat input | mapper | sort | reducer > output 進行單機測試即可。
如果單機測試通過,大多數情況是可以在集羣上成功運行的,只要控制好內存就好了。
2 提高程序效率
有些程序對內存要求較高,如果用java控制內存畢竟不如C/C++。
Streaming不足
1 Hadoop Streaming默認只能處理文本數據,無法直接對二進制數據進行處理
2 Streaming中的mapper和reducer默認只能向標準輸出寫數據,不能方便地處理多路輸出
具體參數介紹
-input <path> |
輸入數據路徑 |
-output <path> |
輸出數據路徑 |
-mapper <cmd|JavaClassName> |
mapper可執行程序或Java類 |
-reducer <cmd|JavaClassName> |
reducer可執行程序或Java類 |
-file <file> Optional |
分發本地文件 |
-cacheFile <file> Optional |
分發HDFS文件 |
-cacheArchive <file> Optional |
分發HDFS壓縮文件 |
-numReduceTasks <num> Optional |
reduce任務個數 |
-jobconf | -D NAME=VALUE Optional |
作業配置參數 |
-combiner <JavaClassName> Optional |
Combiner Java類 |
-partitioner <JavaClassName> Optional |
Partitioner Java類 |
-inputformat <JavaClassName> Optional |
InputFormat Java類 |
-outputformat <JavaClassName>Optional |
OutputFormat Java類 |
-inputreader <spec> Optional |
InputReader配置 |
-cmdenv <n>=<v> Optional |
傳給mapper和reducer的環境變量 |
-mapdebug <path> Optional |
mapper失敗時運行的debug程序 |
-reducedebug <path> Optional |
reducer失敗時運行的debug程序 |
-verbose Optional |
詳細輸出模式 |
下面是對各個參數的詳細說明:
l -input <path>:指定作業輸入,path可以是文件或者目錄,可以使用*通配符,-input選項可以使用多次指定多個文件或目錄作爲輸入。
l -output <path>:指定作業輸出目錄,path必須不存在,而且執行作業的用戶必須有創建該目錄的權限,-output只能使用一次。
l -mapper:指定mapper可執行程序或Java類,必須指定且唯一。
l -reducer:指定reducer可執行程序或Java類,必須指定且唯一。
l -file, -cacheFile, -cacheArchive:分別用於向計算節點分發本地文件、HDFS文件和HDFS壓縮文件。
l -numReduceTasks:指定reducer的個數,如果設置-numReduceTasks 0或者-reducer NONE則沒有reducer程序,mapper的輸出直接作爲整個作業的輸出。
-jobconf | -D NAME=VALUE:指定作業參數,NAME是參數名,VALUE是參數值,可以指定的參數參考hadoop-default.xml。特別建議用-jobconf mapred.job.name='My Job Name'設置作業名,使用-jobconf mapred.job.priority=VERY_HIGH | HIGH | NORMAL | LOW | VERY_LOW設置作業優先級,使用-jobconf mapred.job.map.capacity=M設置同時最多運行M個map任務,使用-jobconf mapred.job.reduce.capacity=N設置同時最多運行N個reduce任務。常見的作業配置參數如下表所示:
mapred.job.name |
作業名 |
mapred.job.priority |
作業優先級 |
mapred.job.map.capacity |
最多同時運行map任務數 |
mapred.job.reduce.capacity |
最多同時運行reduce任務數 |
hadoop.job.ugi |
作業執行權限 |
mapred.map.tasks |
map任務個數 |
mapred.reduce.tasks |
reduce任務個數 |
mapred.job.groups |
作業可運行的計算節點分組 |
mapred.task.timeout |
任務沒有響應(輸入輸出)的最大時間 |
mapred.compress.map.output |
map的輸出是否壓縮 |
mapred.map.output.compression.codec |
map的輸出壓縮方式 |
mapred.output.compress |
reduce的輸出是否壓縮 |
mapred.output.compression.codec |
reduce的輸出壓縮方式 |
stream.map.output.field.separator |
map輸出分隔符 |
l -combiner:指定combiner Java類,對應的Java類文件打包成jar文件後用-file分發。
l -partitioner:指定partitioner Java類,Streaming提供了一些實用的partitioner實現,參考KeyBasedFiledPartitoner和IntHashPartitioner。
l -inputformat, -outputformat:指定inputformat和outputformat Java類,用於讀取輸入數據和寫入輸出數據,分別要實現InputFormat和OutputFormat接口。如果不指定,默認使用TextInputFormat和TextOutputFormat。
l -cmdenv NAME=VALUE:給mapper和reducer程序傳遞額外的環境變量,NAME是變量名,VALUE是變量值。
l -mapdebug, -reducedebug:分別指定mapper和reducer程序失敗時運行的debug程序。
l -verbose:指定輸出詳細信息,例如分發哪些文件,實際作業配置參數值等,可以用於調試。
提交hadoop任務示例:
$HADOOP_HOME/bin/hadoop streaming \
-input /user/test/input -output /user/test/output \
-mapper “mymapper.sh” -reducer “myreducer.sh” \
-file/home/work/mymapper.sh \
-file /home/work/myreducer.sh \
-jobconf mapred.job.name=”file-demo”
上面的命令提交了一個hadoop任務,輸出和輸入分別爲 /user/test/output 和/user/test/input。 map程序爲 mymapper.sh,reduce程序爲myreducer.sh。這裏需要注意一定要將這兩個文件用-file分發到集羣的節點上。最後一行指定了任務的名字。
還有一些較爲複雜的使用,比如需要指定任務個數等,可以使用
-jobconf mapred.job.map.capacity=m -jobconf mapred.job.reduce.capacity=n
上面的命令設置最多同時運行m個map任務,n個reduce任務,如果m或n爲0或者沒有指定,則對應的capacity沒有限制,默認配置就是0沒有限制。建議在運行作業時都設置map和reduce capacity,防止作業佔用過多資源。
當然,這裏只是簡單介紹了最基本的用法,hadoop streaming還有很多高級使用方法,可一些很強大的排序指定功能,這裏不再過多介紹,有需要的朋友可以給我留言進行詢問,只要我遇到過的問題一定給出解決方案。如果運行時出現錯誤,可以參見我的另一篇文章——hadoop錯誤碼
前兩篇文章介紹了Hadoop Streaming框架的使用方法。由於篇幅所限,並沒有介紹其中的高級使用方法,但是有一些用法還是相當常見的。今天對一些高級用法進行一個簡單的說明,希望能給大家一些啓發。
1 使用cacheFile分發文件
如果文件(如字典文件)存放在HDFS中,希望計算時在每個計算節點上將文件當作本地文件處理,,可以使用-cacheFile hdfs://host:port/path/to/file#linkname選項在計算節點緩存文件,Streaming程序通過./linkname訪問文件。
例如:
hadoop = `which hadoop`
$hadoop streaming \
-input /user/test/input -output /user/test/output \
-mapper mymapper.sh -reducer myreducer.sh \
-file /home/work/mymapper.sh \
-file /home/work/myreducer.sh \
-cacheFile hdfs://namenode:port/user/test/dict.data#dictlink \
-jobconf mapred.job.name=”cache-file-demo”
mymapper.sh和myreducer.sh可以通過./dictlink直接訪問字典文件hdfs://user/test/dict.data,而且是從本地讀取文件。
2 用cacheArchive分發壓縮包
有時要分發的文件有一定的目錄結構,可以先將整個目錄打包,然後整體進行上傳。使用-cacheArchive hdfs://host:port/path/to/archivefile#linkname分發壓縮包。
例如在本地有一個目錄爲app,裏面有mapper.pl, reducer.pl, dict/dict.txt這些子目錄和文件,mapper.pl和reducer.pl要讀取./dict/dict.txt文件,希望在任務執行時不需要修改程序和目錄結構, 可以按照下面的方式分發app目錄:
$ tar app.tar.gz –C app . #本地打包
$ $HADOOP_HOME/bin/hadoop fs –put app.tar.gz /user/test/app.tar.gz #包上傳到HDFS
$ $HADOOP_HOME/bin/hadoop streaming \
-input /user/test/input -output /user/test/output \
-mapper “perl app/mapper.pl” -reducer “perl app/reducer.pl” \
-cacheArchive hdfs://namenode:port/user/test/ app.tar.gz #app \
-jobconf mapred.job.name=”cache-archive-demo”
首先將本地app目錄中的所有文件和目錄打包壓縮,然後上傳到HDFS的/user/test/app.tar.gz,啓動streaming任務時使用-cacheArchive選項將app.tar.gz分發到計算節點並解壓到app目錄,然後在當前工作目錄創建到app目錄的鏈接,-mapper選項指定app/mapper.pl爲mapper程序,-reducer選項指定app/reducer.pl爲reducer程序,它們都可以讀取./dict/dict.txt文件。本地打包時要進入目錄app而不是在app的上層目錄打包,否則要通過app/app/mapper.pl才能訪問到mapper.pl文件。
hadoop支持zip, jar, tar.gz格式的壓縮包,由於Java解壓zip壓縮包時會丟失文件權限信息而且遇到中文文件名會出錯,所見建議採用tar.gz壓縮包。
三種文件分發方式的區別:-file將客戶端本地文件打成jar包上傳到HDFS然後分發到計算節點,-cacheFile將HDFS文件分發到計算節點,-cacheArchive將HDFS壓縮文件分發到計算節點並解壓。
3輸出數據分割
默認情況下Streaming框架將map輸出的每一行第一個”\t”之前的部分作爲key,之後的部分作爲value,key\tvalue又作爲reduce的輸入。可以用-D stream.map.output.field.separator改變map輸出中key和value的分隔符,用-D stream.num.map.output.key.fields設置分隔符的位置,該位置之前的部分作爲key,之後的部分作爲value。如下所示,其中-D stream.map. output.field.separator=:指定使用冒號”:”將map輸出的一行分隔爲key/value,-D stream.num.map.output.key.fields=2指定在第二個冒號處進行分隔,也就是第二個冒號之前的作爲key,之後的作爲value。如果沒有冒號或冒號少於兩個,則key爲整行,value爲空。
$HADOOP_HOME/bin/hadoop streaming \
-D stream.map.output.field.separator=: \
-D stream.num.map.output.key.fields=2 \
-input /user/test/input -output /user/test/output \
-mapper mymapper.sh -reducer myreducer.sh \
-file /home/work/mymapper.sh \
-file /home/work/myreducer.sh \
-jobconf mapred.job.name=”output-sep-demo”
與map類似,對於reduce的輸出,同樣也可以用-D stream.reduce.output.field.separator和-D stream.num.reduce.output.key.fields定製key/value分隔方式。
4 二次排序
KeyFieldBasedPartitioner是Hadoop庫中的一個實用Partitioner,配置相應的參數就可以使用,通過KeyFieldBasedPartitioner可以方便地實現二次排序。
$HADOOP_HOME/bin/hadoop streaming \
-D stream.map.output.field.separator=. \
-D stream.num.map.output.key.fields=4 \
-D map.output.key.field.separator=. \
-D num.key.fields.for.partition=2 \
-input /user/test/input -output /user/test/output \
-mapper “mymapper.sh” -reducer “ myreducer.sh” \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \
-file /home/work/mymapper.sh \
-file /home/work/myreducer.sh \
-jobconf mapred.job.name=”key-partition-demo”
其中-Dstream.map.output.field.separator=.和-D stream.num.map.output.key.fields=4與上面的定製輸出數據分隔方式意義相同,指定map的輸出行第4個英文句號”.”之前爲key,後面爲value。-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner指定使用KeyFieldBasedPartitioner,-D map.output.key.field.separator=.指定key的內部用英文句號”.”分隔,-D num.key.fields.for.partition=2指定將key分隔出來的前兩個部分而不是整個key用於Partitioner做partition。
以上就是我個人認爲hadoop streaming中比較常用的技巧,希望對大家有所幫助,同時也多多補充。