一、MapReduce概述
二、MapReduce基礎示例——WorldCount(統計單詞個數)代碼講解:
此例中新舊版API的差別:
1). 新的api放在:org.apache.hadoop.mapreduce,舊版api放在:org.apache.hadoop.mapred
2). 新版api使用虛類,而舊版的使用的是接口,虛類更加利于擴充。
InputValue類中繼承了Mapper類中的map方法講解:
這裡有三個參數,LongWritable key,Text value就是輸入的key和value,第三個參數Context context這是記錄輸入的key和value,例如:context.write(word,one);此外context還會記錄map運算的狀态。
我的了解:
一個有三行文本的檔案進行MapReduce操作。
讀取第一行Hello World Bye World ,分割單詞形成Map。
讀取第二行Hello Hadoop Bye Hadoop ,分割單詞形成Map。
讀取第三行Bye Hadoop Hello Hadoop,分割單詞形成Map。

OutputValue繼承了Reducer類中的reduce方法詳解:
reduce函數輸入也是一個key/value的形式,不過它的value是一個疊代器的形式Iterator values,也就是說reduce的輸入是一個key對應一組值得value,reduce也有context和map的context作用一緻。
Reduce操作是對map的結果進行排序,合并,最後得出詞頻。
經過進一步處理(combiner),将形成的Map根據相同的key組合成value數組。
循環執行Reduce(K,V[]),分别統計每個單詞出現的次數。
main函數的調用
首先:
運作mapreduce程式前都要初始化Configuration,該類主要是讀取mapreduce系統配置資訊,這些資訊包括hdfs還有mapreduce,也就是安裝hadoop時候的配置檔案,例如 core-site.xml、hdfs-site.xml和mapred-site.xml等等檔案裡的資訊。我們程式員開發mapreduce時候隻是在填空,在map函數和reduce函數裡編寫實際進行的業務邏輯,其它的工作都是交給mapreduce架構自己操作的,但是至少我們要告訴它怎麼操作啊,比如hdfs在哪裡啊,mapreduce的jobstracker在哪裡啊,而這些資訊就在conf包下的配置檔案裡。
接下來的代碼是:
if的語句好了解,就是運作WordCount程式時候一定是兩個參數,如果不是就會報錯退出。至于第一句裡的GenericOptionsParser類,它是用來解釋常用hadoop指令,并根據需要為Configuration對象設定相應的值,其實平時開發裡我們不太常用它,而是讓類實作Tool接口,然後再main函數裡使用ToolRunner運作程式,而ToolRunner内部會調用GenericOptionsParser。
第一行就是在建構一個job,在mapreduce架構裡一個mapreduce任務也叫mapreduce作業也叫做一個mapreduce的job,而具體的map和reduce運算就是task了,這裡我們建構一個job,建構時候有兩個參數,一個是conf這個就不累述了,一個是這個job的名稱。
第二行就是裝載程式員編寫好的計算程式,例如我們的程式類名就是WordCount了。這裡我要做下糾正,雖然我們編寫mapreduce程式隻需要實作map函數和reduce函數,但是實際開發我們要實作三個類,第三個類是為了配置mapreduce如何運作map和reduce函數,準确的說就是建構一個mapreduce能執行的job了,例如WordCount類。
第三行和第五行就是裝載map函數和reduce函數實作類了,這裡多了個第四行,這個是裝載Combiner類,這個我後面講mapreduce運作機制時候會講述,其實本例去掉第四行也沒有關系,但是使用了第四行理論上運作效率會更好。
這個是定義輸出的key/value的類型,也就是最終存儲在hdfs上結果檔案的key/value的類型。
第一行就是建構輸入的資料檔案,第二行是建構輸出的資料檔案,最後一行如果job運作成功了,我們的程式就會正常退出。
三、MapReduce運作機制
圖1:
圖2:
首先講講實體實體,參入mapreduce作業執行涉及4個獨立的實體:
下面我從邏輯實體的角度講解mapreduce運作機制,這些按照時間順序包括:輸入分片(input split)、map階段、combiner階段、shuffle階段和reduce階段。
2)、map階段:就是程式員編寫好的map函數了,是以map函數效率相對好控制,而且一般map操作都是本地化操作也就是在資料存儲節點上進行;
3)、combiner階段:combiner階段是程式員可以選擇的,combiner其實也是一種reduce操作,是以我們看見WordCount類裡是用reduce進行加載的。Combiner是一個本地化的reduce操作,它是map運算的後續操作,主要是在map計算出中間檔案前做一個簡單的合并重複key值的操作,例如我們對檔案裡的單詞頻率做統計,map計算時候如果碰到一個hadoop的單詞就會記錄為1,但是這篇文章裡hadoop可能會出現n多次,那麼map輸出檔案備援就會很多,是以在reduce計算前對相同的key做一個合并操作,那麼檔案會變小,這樣就提高了寬帶的傳輸效率,畢竟hadoop計算力寬帶資源往往是計算的瓶頸也是最為寶貴的資源,但是combiner操作是有風險的,使用它的原則是combiner的輸入不會影響到reduce計算的最終輸入,例如:如果計算隻是求總數,最大值,最小值可以使用combiner,但是做平均值計算使用combiner的話,最終的reduce計算結果就會出錯。
4)、 shuffle階段:将map的輸出作為reduce的輸入的過程就是shuffle了,這個是mapreduce優化的重點地方。這裡我不講怎麼優化shuffle階段,講講shuffle階段的原理,因為大部分的書籍裡都沒講清楚shuffle階段。Shuffle一開始就是map階段做輸出操作,一般mapreduce計算的都是海量資料,map輸出時候不可能把所有檔案都放到記憶體操作,是以map寫入磁盤的過程十分的複雜,更何況map輸出時候要對結果進行排序,記憶體開銷是很大的,map在做輸出時候會在記憶體裡開啟一個環形記憶體緩沖區,這個緩沖區專門用來輸出的,預設大小是100mb,并且在配置檔案裡為這個緩沖區設定了一個閥值,預設是0.80(這個大小和閥值都是可以在配置檔案裡進行配置的),同時map還會為輸出操作啟動一個守護線程,如果緩沖區的記憶體達到了閥值的80%時候,這個守護線程就會把内容寫到磁盤上,這個過程叫spill,另外的20%記憶體可以繼續寫入要寫進磁盤的資料,寫入磁盤和寫入記憶體操作是互不幹擾的,如果緩存區被撐滿了,那麼map就會阻塞寫入記憶體的操作,讓寫入磁盤操作完成後再繼續執行寫入記憶體操作,前面我講到寫入磁盤前會有個排序操作,這個是在寫入磁盤操作時候進行,不是在寫入記憶體時候進行的,如果我們定義了combiner函數,那麼排序前還會執行combiner操作。每次spill操作也就是寫入磁盤操作時候就會寫一個溢出檔案,也就是說在做map輸出有幾次spill就會産生多少個溢出檔案,等map輸出全部做完後,map會合并這些輸出檔案。這個過程裡還會有一個Partitioner操作,對于這個操作很多人都很迷糊,其實Partitioner操作和map階段的輸入分片(Input split)很像,一個Partitioner對應一個reduce作業,如果我們mapreduce操作隻有一個reduce操作,那麼Partitioner就隻有一個,如果我們有多個reduce操作,那麼Partitioner對應的就會有多個,Partitioner是以就是reduce的輸入分片,這個程式員可以程式設計控制,主要是根據實際key和value的值,根據實際業務類型或者為了更好的reduce負載均衡要求進行,這是提高reduce效率的一個關鍵所在。到了reduce階段就是合并map輸出檔案了,Partitioner會找到對應的map輸出檔案,然後進行複制操作,複制操作時reduce會開啟幾個複制線程,這些線程預設個數是5個,程式員也可以在配置檔案更改複制線程的個數,這個複制過程和map寫入磁盤過程類似,也有閥值和記憶體大小,閥值一樣可以在配置檔案裡配置,而記憶體大小是直接使用reduce的tasktracker的記憶體大小,複制時候reduce還會進行排序操作和合并檔案操作,這些操作完了就會進行reduce計算了。
5)、reduce階段:和map函數一樣也是程式員編寫的,最終結果是存儲在hdfs上的。
MapReduce是運作在yarn上的一個應用。
Map任務執行的數量是由InputSplit數量決定的。InputSplit的數量由什麼決定?
1、InputSplit的大小預設是hdfs的block(資料塊,預設是128M)大小。
2、如果檔案大小小于block,那麼就是一個InputSplit;
假設有一個300MB的檔案和一個100MB檔案,那麼有多少個InputSplit?
首先,300MB的檔案是2*128M+44MB,也就是說分成了2個InputSplit還多了一部分,
那麼這一部分又會分成一個InputSplit。是以總共是4個InputSplit。
本文轉自 yntmdr 51CTO部落格,原文連結:http://blog.51cto.com/yntmdr/1890802,如需轉載請自行聯系原作者