1. Hadoop包含兩核心部分
- hdfs
- Hadoop distribute file system -- hadoop分佈式文件系統,存儲數據
- Namenode、Datanode
- 常用命令形式:hadoop fs -ls / hadoop fs -mkdir
- MapReduce
- 分而治之;map:實現分治;reduce:實現合併
- 解決數據可分割的計算問題
- 編程接口:常用Streaming;組成:Job配置文件、map函數,reduce函數
2. hdfs結構圖
- Namenode存儲元數據,數據信息,數據備份信息
- Datanode 數據備份:本機架備份、異地備份
3. MapReduce調度框架
- JobClient: 負責根據用戶指定參數生成一個mapreduce作業,提交到JobTracker
- JobTracker: 單Master節點,將Job所有task調度到TaskTracker
- TaskTracker: 部署在每臺計算機節點的一個service
4. MapReduce 執行層
- Map階段,讀入數據,通過partition聚集相同key數據,並寫到本機磁盤
- Reduce階段,不同reduce,讀入Map階段各maps的相應輸出
5. streaming 作業
- streaming mapper
- 先啓動用戶提交作業時指定的一個外部程序,一般是腳本
- 這個外部程序作爲streaming mapper的子進程,streaming mapper讀取用戶輸入後,不再是調用map函數處理,而是通過管道寫到子進程的標準輸入
- 從子進程的標準輸出讀取數據,寫到磁盤上
- streaming 作業數據流向
- 父進程是Java,負責讀取數據通過管道發送給子進程
- 通過管道把結果再讀取回來
一份數據在兩個不同進程中傳遞兩次
6 mapreduce – shuffle
- map --> shuffle –> reduce
- shuffle 從多個節點傳遞到多個節點,而不是多個節點到一個節點
- shuffle 包含partition、combiner
- partition : 數據歸併,分割map每個節點的結果,按照key分別映射給不同的reduce,默認是HashPartition,which reducer == (key.hashCode & Integer.MAX_VALUE)% numReduceTasks
- 作用:計算(key, value)所屬分區 ; 把同一分區數據合併、聚集
- combiner: combiner屬於優化方案,由於帶寬限制,應該儘量map和reduce之間的數據傳輸數量。它在Map端把同一個key的鍵值對合並在一起並計算,計算規則與reduce一致,所以combiner也可以看作特殊的Reducer
7. streaming 常用配置項
- stream.map.output.field.separator // 該參數屬於streaming作業參數,設置map輸出的字段分隔符,默認爲“\t”,該分隔符只對下面的stream.num.map.output.key.fields參數生效
- stream.num.map.output.key.fields // 設置map輸出的前幾個字段作爲key,一般與第二項stream.map.output.field.separator 結合使用
- mapred.text.key.partitioner.options // 設置key內某個字段或者某個字段範圍用做partition
- mapred.text.key.comparator.options // 設置key中需要比較的字段或字節範圍
- partitioner // 主要用於對鍵值進行劃分,負責將map的輸出結果根據key進行分割。Key用於確定不同的key落到不同的reduce上,通常對key進行Hash以後對reduce取mod,該key對應的紀錄最終將根據mod值落到對應的reduce上進行處理。HashPartitioner, IndexUpdatePartitioner, KeyFieldBasedPartitioner, SleepJob,默認的爲 HashPartitioner,即對key直接進行hash分到對應的reduce,具體見第6部分。更高級一點的爲 KeyFieldBasedPartitioner,該partitioner可以指定key中前幾個字段用於分割
- HashPartition 最基本的Partitioner,如果不指定Partitioner的話則默認使用該類。輸出格式爲最基本的key”\t“value
- KeyFieldBasedPartitioner 可以看做HashPartitioner的擴展,他將原有的對單字段Key的hash擴展到可以靈活地對多字段key進行分桶並排序,對應配置參數如下:
- -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner // 該參數表示作業啓用KeyFieldBasedParitioner
- -D map.ouput.key.field.separator // 該參數屬於KeyFieldBasedPartitioner參數,只有當啓用KeyFieldBasedParititioner時,該參數纔會生效;該參數指明map輸出結果中字段之間的分隔符(該分隔符只對下面的num.key.fields.for.partition參數生效);
- -D num.key.fields.for.partition // 該參數同樣屬於KeyFieldBasedPartitioner參數;該參數指明map輸出結果的key按上述分隔符切分後,前幾個字段將用來做partition;該參數不能與mapred.text.key.partitioner.options共用;
- -D mapred.text.key.partitioner.options // 該參數同樣屬於KeyFieldBasedPartitioner參數; 該參數指明map輸出結果的key按上述分隔符切分後,使用哪些字段用來做partition;該參數不能與num.key.fields.for.partition共用,一起使用則以num.key.fields.for.partition爲準;
- KeyFieldBaseComparator // 可以靈活設置比較位置的高級比較器,但是它和沒有自己獨有的比較邏輯,而是使用默認Text的基於字典序或者通過-n來基於數字比較,直觀來說,partition指定key中的分區元素,KeyFieldBaseComparator用作指定key排序字段以及排序規則,參數配置如下:
- -D mapred.output.key.comparator.class=org.apache.hadoop.mapred.lib.KeyFieldBasedComparator // 該參數表示作業啓用KeyFieldBasedComparator
- -D mapred.text.key.comparator.options="-k3,3 -k4nr" // 以key中第三個字段正序,第四個字段逆序比較排序
- stream.memory.limit // 任務內存限制
- mapred.reduce.tasks // 指定reducer個數
- cmdenv //傳遞給streaming命令的環境變量
- -input //HDFS目錄或文件路徑, Mapper的輸入數據,文件要在任務提交前手動上傳到HDFS
- -output // reducer輸出結果的HDFS存放路徑, 不能已存在,但腳本中一定要配置,多次-input,指定多個輸入文件
- -mapper // 可執行命令,mapper程序
- -reducer // 可執行命令, reduce程序,不需要reduce處理就不指定
- -file //本地mapper、reducer程序文件、程序運行需要的其他文件,將本地文件分發給計算節點;文件作爲作業的一部分,一起被打包並提交,所有分發的文件最終會被放置在datanode該job的同一個專屬目錄下:jobcache/job_xxx/jar
- -cacheFile //分發HDFS文件
- -cacheArchive // 分發HDFS壓縮文件、壓縮文件內部具有目錄結構
- mapred.job.priority //作業優先級
- mapred.job.map.capacity // 最多同時運行map任務數
- mapred.job.reduce.capacity //最多同時運行reduce任務數
- mapred.job.name // job name
8. key-partition 實例
- key 不等於 partition,也就是說,分桶規則跟map階段的key有可能不是一回事
- 假設,文件A中內容如下:
- 第一種作業方式(部分參數):
./hadoop streaming
-D stream.map.output.field.separator=.
-D stream.num.map.output.key.fields=2
只是將map的輸出結果按兩個字段切分成了key和value;再分桶上我們可以看出,它是以前兩個字段作爲一個整體來進行分桶的,e.5與e.9沒有分在一個reduce
- 第二種作業:
./hadoop streaming
-D stream.map.output.field.separator=.
-D stream.num.map.output.key.fields=2
-D map.output.key.field.separator=.
-D num.key.fields.for.partition=1
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner\
這裏啓用了KeyFieldBasedPartitioner,並且制定分桶以key的第一個字段爲準;我們可以看出mapred依然採用的是前兩個字段爲key,但是在分桶上只對第一個字段做了哈希函數,因此這次e.5和e.9分到了一個reducer內
- 第三種作業
./hadoop streaming
-D stream.map.output.field.separator=.
-D stream.num.map.output.key.fields=3
-D map.output.key.field.separator=.
-D num.key.fields.for.partition=1
-D mapred.text.key.partitioner.options=-k2,3
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner
這次將key的長度改成3個字段,分桶標準也變成key的第2、3個字段,可以看出e.5.1被分在了一起,而第三個字段不同的e.5.9被分到了其他的reducer中
- 第四種作業
./hadoop streaming \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \
-D mapred.output.key.comparator.class=org.apache.hadoop.mapred.lib.KeyFieldBasedComparator \
-D stream.num.map.output.key.fields=4 \
-D stream.map.output.field.separator=. \
-D map.output.key.field.separator=. \
-D mapred.text.key.partitioner.options=-k1,2 \
-D mapred.text.key.comparator.options="-k3,3 -k4nr" \
這次key的長度爲4,分桶標準爲key的第一、二個字段,可以看出,e.5被分到一個桶內,而輸出結果,按照key的第三個字段的正序,第四個字段的逆序排列輸出