概念簡述
簡介
MapReduce是一種計算框架,計算模型用來解決海量數據計算問題。在運行時一部分負責管理叫MRAppMaster運行在yarn容器中,剩下的統稱爲任務task也是在yarn容器中運行。
MR分爲Map階段和Reduce階段,Map讀取hdfs中的數據經過處理後交給Reduce進行處理將結果存入hdfs中。實際工作中我們只需要實現map,reduce,dirver階段的工作,其他的讀取傳輸排序組合由框架完成。
Map任務爲一個java進程分佈式運行在很多節點上,這樣hdfs的海量數據就可以被很多的map任務處理。一個block對應一個map任務,比如hdfs數據由3個block組成就會有3個map任務來處理,這樣可以並行進行數據處理。
Map處理的結果會交給Reduce任務,而一般map任務和reduce任務不在同一個節點,map通過網絡將數據傳輸給reduce,map和reduce分佈執行不同的邏輯。Map讀取hdfs數據是按照一行一個<k1,v1>鍵值對的形式進行讀取的,K1爲字節順序,v1爲一行的內容。
例
文件hello
twofour
one two three
map函數
public void map(k1,v1,context){
context.write(k2,v2);//執行map處理邏輯
}
Hdfs的文件hello中的會被解析爲<0,two four>和<9,one two three>,第二行的第一個字節順序是9。
框架會對map輸出的<k2,v2>進行排序和分組。排序是按照k2進行排序,分組將k2相同的v2分到一組,整個排序分組不會改變<k2,v2>的數量。排序分組完成後交給reduce處理,有的時候沒有reduce階段那麼map的輸出就直接寫入到hdfs中。
Reduce函數
publicvoid reduce(k2,v2s,context){//v2s就是k2相同的v2的集合
context.write(k3,v3);//執行reduce邏輯
}
在複雜情況下map節點會向不同的reduce階段輸出數據
執行過程:
Map階段:
1:框架使用inputFormat的子類把輸入文件或目錄下的所有文件(不支持遞歸)劃分爲很多的inputsplit,默認一個block對應一個inputsplit,一個inputsplit對應一個map任務。然後通過recordReader把每個inputsplit解析爲很多的<k,v>鍵值對,一行一個鍵值對。
2:框架調用Mapper類中的map函數進行邏輯處理我們可以自己覆蓋這個函數,參數返回值均爲<k,v>鍵值對。
3:若無reduce則直接寫入hdfs中,結束。
有reduce框架會對<k,v>鍵值對進行分區,不同分區的鍵值對會輸從給不同的reduce,默認一個分區。
4:對分區中的鍵值對進行排序分組。
5:在map節點上可以執行reduce歸約
6:將排序分組後的鍵值對存入到linux磁盤上。
Reduce階段
1:框架會將多個map任務的輸出按照不同的分區拷貝到不同的reduce節點上,這個過程叫做shuffle。
2:框架會對reduce接收的多個map的相同分區的<k,v>鍵值對進行合併。
3:框架調用reducer類的reduce方法,入參<k2,{v2}>輸出<k3,v3>,一個<k2,{v2}>調用一次reduce函數我們可以覆蓋這個函數實現自己的邏輯。
4:框架將reduce的輸出保存到hdfs中,每個reduce任務輸出一個文件,整個MR過程會輸出一個目錄,但是框架不能把目錄下的文件合併。
下面是一個很簡化的流程圖,數據從左往右走
Shuffle過程簡介
1. MAP任務處理完畢之後先將數據存入內存。
2. 緊接着對內存中的數據執行分區排序操作並存入磁盤,此時磁盤中就存在很多的小片用於存儲。(寫1)
3. 讀取磁盤上小分片中的數據然後merge寫入一個大文件,這個大文件中包含很多分區。(讀1+寫2)
4. 此時磁盤上會有很多的大文件,每個文件上的分區數據會輸出給不同節點上的reduce任務(讀3),這步操作應該還會產生IO消耗。
5. Reduce任務所在節點讀取完畢後再對其進行merge操作形成一個大文件寫入磁盤(寫3)。
6. 最後reduce任務讀取這個大文件作爲自己的入參來進行計算。
以上就是hadoop中shuffle的簡單過程,統計一下讀寫磁盤共有6次。Spark也有shuffle過程但是全部是基於內存的所以比hadoop快。