hadoop mr數據流總結

原址:http://kissmett.iteye.com/blog/1887946

hadoop mr數據流 
Java代碼  收藏代碼
  1. /* 
  2. 符注: 
  3. ()內爲數據;[]內爲處理; 
  4. {}內爲框架模塊; 
  5. ()數據若無說明則爲在內存; 
  6. ->本機數據流;=>網絡數據流;~>分佈式-本地讀寫數據流; 
  7. /**/爲標註;  
  8. */  
  9. (分佈式源文件)~>{JobTracker分配到各TaskTracker本機上}=>  
  10. -------------------------------- @TaskTracker(Map) machine  
  11. (split)->[InputFormat]->  
  12. [RecordReader]迭代begin  
  13.     (k1,v1)->[map]->  
  14.     (k2,v2)->[partition]->  
  15. [RecordReader]迭代end->  
  16. (k2,v2內存集合1)->[sort,merge]->  
  17. (k2,v2內存排序集合)->  
  18. [combine]迭代begin/*若有partition則按其規則*/  
  19.     (k2,iter(v2))->[combine]->  
  20.     (k3,v3)->  
  21. [combine]迭代end->  
  22. (k3,iter(v3)本地文件)->  
  23. -------------------------------- @TaskTracker(Map) machine  
  24. [shuffle]=>  
  25. -------------------------------- @TaskTracker(Reduce) machine  
  26. (k3,iter(v3)來自各mapper的子集)->[sort,merge]->  
  27. (k3,iter(v3)來自各mapper的合集)->[reduce]->  
  28. (k4,v4)->[OutputFormat]~>  
  29. -------------------------------- @TaskTracker(Reduce) machine  
  30. (分佈式結果文件)  


====================================== 
總結mapreduce數據處理流程: 
所謂分佈式計算在hadoop的實現裏可表達爲: 
1.基於hdfs分佈式存儲的各存儲節點的map運算過程; 
2.之後的在少量(甚至唯一)節點上的reduce運算過程; 
3.以及連接map運算輸出和reduce輸入的shuffle過程; 
下圖表達在某datanode機器節點進行map和shuffle的過程: 


InputFomat:從block到split到(k1,v1) 
hdfs中文件是按照配置大小(默認64M)分block存儲n份(一般爲)到n個獨立datanode節點的; 
當要解析某分佈式文件,要執行map任務的TaskTracker將讀取存儲於本機的相關block進行本地文件解析; 
個人理解是一個block可以被拆分爲多個split,每個split作爲一個map tasktracker的輸入(但如何切分還沒搞清楚),我所涉及的所有mr測試中都是一個block對應一個map任務. 
這個split可以通過FSDataInputStream輸入流讀取,這是一個本地文件讀取操作. 
此過程中可以編寫自己的InputFormat進行自定義的讀取,此類功能的核心是返回一個RecordReader,RR是具體解析文件邏輯實現類: 
對於hadoop0.20及以前版本,對應hadoop core jar裏的 org.apache.hadoop.mapred包,RR我理解是一種被動模式,從其接口函數命名看,主要實現如下函數: 
Java代碼  收藏代碼
  1. createKey()  
  2. createValue()  
  3. getPos()  
  4. next(Text key, Text value)  

這個RecordReader接口具體實現類的調用者,應是先調用createKey和createValue來實例化key,value對象(這裏是爲初始化自定義對象考慮的),然後再調用next(key,value)來填充這兩個對象而得到解析的結果. 
對於hadoop1.0及之後的版本,對應hadoop core jar裏的 org.apache.hadoop.mapreduce包,RR是一種主動模式,主要實現如下函數: 
Java代碼  收藏代碼
  1. getCurrentKey()  
  2. getCurrentValue()  
  3. nextKeyValue()  
  4. getPos()  
  5. isSplitable(JobContext context, Path file)  

此接口調用者,應是直接調用nextKeyValue()來獲取key value實例,然後通過兩個getCurrent方法由調用者獲取其對應實例; 
無論是next(Text key, Text value),還是nextKeyValue(),split被RR解析爲一條的(k1,v1) 
MapClass.map():從(k1,v1)到(k2,v2) 
不多說. 

Partition.partition():給(k2,v2)蓋章(指定reduce) 
經過此函數數據流中的k,v是不變的,函數相當於給此k,v對蓋個章,指定其要去的reduce. 
值得注意的是,經過RR出來的(k1,v1)是先順序經過map和partition,而非全過完map之後再全過partition. 

所有(k2,v2)寫入membuffer. 
經過InputFormat中RR的next/nextKeyValue迭代,形成的系列(k2,v2)會被寫入到內存的buffer中,此buffer大小通過io.sort.mb參數指定. 
另爲了控制資源,會有另一個進程來監控此buffer容量,當實際容量達到/超過此buffer某百分比時,將發生spill操作,此百分比通過io.sort.spill.percent參數設定. 
此監控進程與寫入獨立,所以不會影響寫入速度. 

spill:mem buffer中的(k2,v2)落地爲local disk的文件 
當buffer實際容量超過門檻限制,或者split所有數據經RR next/nextKeyValue迭代完成時,均觸發spill操作,所以每個map任務流中至少會有一次spill. 
spill作用是將buffer裏的kv對sort到本地磁盤文件. 
sort:針對spill kv數據的排序 
在spill時,sort會參考partition時給數據所蓋的章,即reduce號,另在reduce號相同的情況下再按照k2排序.這個排序至少有兩個目的: 
1.使得在有可能的combine中進行同key的迭代變的很容易; 
2.使得shuffle後的reduce大流程中基於同key合併變得相對容易; 

combine:從(k2,iter(v2))到(k3,v3) 
combine類建立的初衷是儘量減少spill發生的磁盤寫操作的量(拿網上通用的說法就是本地的reduce,也確實是實現了Reduce的接口/父類) 
combine基於業務規則處理key及同key的所有value.這(k2,iter(v2))經處理後,僅返回一個(k3,v3),減少了spill磁盤寫入量. 
combine很有意思,特別是當它跟partition聯合來使用時,在此我在理解上了也頗費了翻功夫: 
partition給(k2,v2)蓋章,決定了這個(k2,v2)具體要到哪個reduce去.而其後的combine處理,我完全隨便寫邏輯來處理同key的(k2,iter(v2)),大家是否也有跟我一樣的疑問:假設我在partition裏是根據value的某種規則來決定reduce號,但到了combine中,某個(k2,v2)卻要跟其他很多(k2,v2')進行處理,而其他(k2,v2')並不一定會在partition根據規則歸到同一個reduce號上,那combine卻籠統的返回了一個(k3,v3),那麼這個(k3,v3)到底是會給哪個reduce呢? 
我理解hadoop在這裏的機制是,在spill時,首先按照partition的reduce號來將分到同reduce的(k2,v2)放到一起,在此前提下,再進行同key的sort,最終寫入到一個與reduce號相關的spill file中(位於local disk).我還沒有去看具體代碼,暫時把這個理解寫這裏. 
另對於這個問題,網上有文章(http://langyu.iteye.com/blog/992916)提及:"Combiner只應該用於那種Reduce的輸入key/value與輸出key/value類型完全一致,且不影響最終結果的場景。比如累加,最大值等。Combiner的使用一定得慎重,如果用好,它對job執行效率有幫助,反之會影響reduce的最終結果。" 
這位作者文章很精彩,我很贊同以上的說法,但,實際上我認爲運用spill的這種特性,可以完成二級(或者多級)統計的功能(見後面一個測試的例子). 

merge and sort:將多個map的spill文件按找partition分配的reduce號歸併 
首先是按照reduce號進行分組,分組內將按照key(即k3)排序. 

shuffle:洗牌,不如稱之爲摸牌 
當一個TaskTracker執行完了map任務,他將完成狀態彙報給JobTracker.這時(我認爲)JobTracker會讓分配reduce的TaskTracker來獲取這個map生成的文件,每個TaskTracker獲取它所執行reduce對應的那份. 

merge and sort:reduce端的 
當TaskTracker從各map機上取得屬於自己的文件後,要執行merge和sort過程,即按照k3進行排序,這樣有利於通過一次遍歷就可以達到輸入(k3,iter(v3))的效果. 

reduce:從(k3,iter(v3))到(k4,v4)並寫入至分佈式文件系統 
每個reduce會生成一個分佈式文件,放置於任務目錄下. 





附:一個測試的例子: 
...經過map的處理到partition, 
partition的輸入(k2,v2)其中k2的含義是書籍出版的年份m個(比如,1999/2010/2012/...),v2的含義是書的分類n個(比如,技術/文學/藝術/...) 
partition的處理是根據value來映射到reduce,即每中書籍分類讓一個reduce處理. 
combine的輸入(k2,iter(v2)),輸出(k3,v3)其中k3=k2;v3=count(iter(v2)); 
reduce的輸入是(k3,iter(v3)),輸出(k4,v4),其中k4=k3;v4=sum(iter(v2)); 
整個mr執行完之後,按書籍分類輸出n個文件,每個文件里根據年份輸出該年份(該分類)的書籍總數; 
達到做二級分類統計的目的 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章