大資料時代之hadoop(五):hadoop 分散式計算框架(MapReduce)
大資料時代之hadoop(三):hadoop資料流(生命週期)
大資料時代之hadoop(四):hadoop 分散式檔案系統(HDFS)
hadoop的核心分為兩塊,一是分散式儲存系統-hdfs,這個我已經在上一章節大致講了一下,另一個就是hadoop的計算框架-mapreduce。
mapreduce其實就是一個移動式的基於key-value形式的分散式計算框架。
其計算分為兩個階段,map階段和reduce階段,都是對資料的處理,由於其入門非常簡單,但是若想理解其中各個環節及實現細節還是有一定程度的困難,因此我計劃在本文中只是挑幾個mapreduce的核心來進行分析講解。
1、MapReduce驅動程式預設值
編寫mapreduce程式容易入手的其中一個原因就在於它提供了一些了的預設值,而這些預設值剛好就是供開發環境設定而設定的。雖然容易入手,但還是的理解mapreduce的精髓,因為它是mapreduce的引擎,只有理解了mapreduce的核心,當你在編寫mapreduce程式的時候,你所編寫的程式才是最終穩重的,想要的程式。廢話少說,見下面程式碼:
public int run(String[] args) throws IOException {
JobConf conf = new JobConf();
/**
*預設的輸入格式,即mapper程式要處理的資料的格式,hadoop支援很多種輸入格式,下面會詳細講解,
*但TextInputFormat是最常使用的(即普通文字檔案,key為LongWritable-檔案中每行的開始偏移量,value為Text-文字行)。
**/
conf.setInputFormat(org.apache.hadoop.mapred.TextInputFormat.class);
/**
*真正的map任務數量取決於輸入檔案的大小以及檔案塊的大小
**/
conf.setNumMapTasks(1);
/**
*預設的mapclass,如果我們不指定自己的mapper class時,就使用這個IdentityMapper 類
**/
conf.setMapperClass(org.apache.hadoop.mapred.lib.IdentityMapper.class);
/**
* map 任務是由MapRunner負責執行的,MapRunner是MapRunnable的預設實現,它順序的為每一條記錄呼叫一次Mapper的map()方法,詳解程式碼 --重點
*/
conf.setMapRunnerClass(org.apache.hadoop.mapred.MapRunner.class);
/**
* map任務輸出結果的key 和value格式
*/
conf.setMapOutputKeyClass(org.apache.hadoop.io.LongWritable.class);
conf.setMapOutputValueClass(org.apache.hadoop.io.Text.class);
/**
* HashPartitioner 是預設的分割槽實現,它對map 任務執行後的資料進行分割槽,即把結果資料劃分成多個塊(每個分割槽對應一個reduce任務)。
* HashPartitioner是對每條 記錄的鍵進行雜湊操作以決定該記錄應該屬於哪個分割槽。
*
*/
conf.setPartitionerClass(org.apache.hadoop.mapred.lib.HashPartitioner.class);
/**
* 設定reduce任務個數
*/
conf.setNumReduceTasks(1);
/**
*預設的reduce class,如果我們不指定自己的reduce class時,就使用這個IdentityReducer 類
**/
conf.setReducerClass(org.apache.hadoop.mapred.lib.IdentityReducer.class);
/**
* 任務最終輸出結果的key 和value格式
*/
conf.setOutputKeyClass(org.apache.hadoop.io.LongWritable.class);
conf.setOutputValueClass(org.apache.hadoop.io.Text.class);
/**
* 最終輸出到文字檔案型別中
*/
conf.setOutputFormat(org.apache.hadoop.mapred.TextOutputFormat.class);/*]*/
JobClient.runJob(conf);
return 0;
}
我要說的大部分都包含在了程式碼的註釋裡面,除此之外,還有一點:由於java的泛型機制有很多限制:型別擦除導致執行過程中型別資訊並非一直可見,所以hadoop需要明確設定map,reduce輸入和結果型別。
上面比較重要的就是MapRunner這個類,它是map任務執行的引擎,預設實現如下:
public class MapRunner<K1, V1, K2, V2>
implements MapRunnable<K1, V1, K2, V2> {
private Mapper<K1, V1, K2, V2> mapper;
private boolean incrProcCount;
@SuppressWarnings("unchecked")
public void configure(JobConf job) {
//通過反射方式取得map 例項
this.mapper = ReflectionUtils.newInstance(job.getMapperClass(), job);
//increment processed counter only if skipping feature is enabled
this.incrProcCount = SkipBadRecords.getMapperMaxSkipRecords(job)>0 &&
SkipBadRecords.getAutoIncrMapperProcCount(job);
}
public void run(RecordReader<K1, V1> input, OutputCollector<K2, V2> output,
Reporter reporter)
throws IOException {
try {
// allocate key & value instances that are re-used for all entries
K1 key = input.createKey();
V1 value = input.createValue();
while (input.next(key, value)) {
// map pair to output
//迴圈呼叫map函式
mapper.map(key, value, output, reporter);
if(incrProcCount) {
reporter.incrCounter(SkipBadRecords.COUNTER_GROUP,
SkipBadRecords.COUNTER_MAP_PROCESSED_RECORDS, 1);
}
}
} finally {
mapper.close();
}
}
protected Mapper<K1, V1, K2, V2> getMapper() {
return mapper;
}
}
要相信,有些時候還是看原始碼理解的更快!
2、shuffle
shuffle過程其實就是從map的輸出到reduce的輸入過程中所經歷的步驟,堪稱mapreduce的“心臟”,分為3個階段,map端分割槽、reduce端複製、reduce排序(合併)階段。
2.1、map端分割槽
由於在mapreduce計算中,有多個map任務和若干個reduce任何,而且各個任務都可能處於不同的機器裡面,所以如何從map任務的輸出到reduce的輸入是一個難點。
map函式在產生輸出時,並不是簡單的寫到磁碟中,而是利用緩衝的形式寫入到記憶體,並出於效率進行預排序,過程如下圖:
在寫磁碟之前,執行緒首先根據reduce的個數將輸出資料劃分成響應的分割槽(partiton)。在每個分割槽中,後臺執行緒按鍵進行內排序,如果有個一combiner,它會在排序後的輸出上執行。
2.2、reduce端複製階段
由於map任務的輸出檔案寫到了本地磁碟上,並且劃分成reduce個數的分割槽(每一個reduce需要一個分割槽),由於map任務完成的時間可能不同,因此只要一個任務完成,reduce任務就開始複製其輸出,這就是reduce任務的複製階段。如上圖所示。
2.3、reduce端排序(合併)階段
複製完所有map輸出後,reduce任務進入排序階段(sort phase),這個階段將合併map輸出,維持其順序排序,如上圖所示。
3、輸入與輸出格式
隨著時間的增加,資料的增長也是指數級的增長,且資料的格式也越來越多,對大資料的處理也就越來越困難,為了適應能夠處理各種各樣的資料,hadoop提供了一系列的輸入和輸出格式控制,其目的很簡單,就是能夠解析各種輸入檔案,併產生需要的輸出格式資料。
但是不管處理哪種格式的資料,都要與mapreduce結合起來,才能最大化的發揮hadoop的有點。
這部分也是hadoop的核心啊!
3.1、輸入分片與記錄
在講HDFS的時候,說過,一個輸入分片就是由單個map任務處理的輸入塊,一個分片的大小最好與hdfs的塊大小相同。
每個分片被劃分成若干個記錄,每個記錄就是一個鍵值對,map一個接一個的處理每條記錄。
在資料庫常見中,一個輸入分片可以對應一個表的若干行,而一條記錄對應一行(DBInputFormat)。
輸入分片在hadoop中表示為InputSplit介面,有InputFormat建立的。
InputFormat負責產生輸入分片並將他們分割成記錄,其只是一個介面,具體任務有具體實現去做的。
3.2、FileInputFormat
FileInputFormat是所有使用檔案作為其資料來源的InputFormat實現的基類,它提供了兩個功能:一個定義哪些檔案包含在作業的輸入中;一個為輸入檔案產生分片的實現。把分片割成基類的作業有其子類實現,FileInputFormat是個抽象類。
FileInputFormat實現了把檔案分割槽的功能,但它是怎麼來實現了呢?需要先說三個引數:
屬性名稱 | 型別 | 預設值 | 描述 |
mapred.min.split.size | Int | 1 | 一個檔案分片的最小位元組數 |
mapred.max.split.size | Long | Long.MAX_VALUE | 一個檔案分片的最大位元組數 |
dfs.block.size | long | 64M | HDFS中塊大小 |
分片的大小有一個公式計算(參考FileInputFomat類的computeSplitSize()方法)
max(minimumSize,min(maximumSize,blockSize))
預設情況下: minimumSize < blockSize < maximumSize
FileInputFormat只分割大檔案,即檔案大小超過塊大小的檔案。
FileInputFormat生成的InputSplit是一整個檔案(檔案太小,未被分割槽,整個檔案當成一個分割槽,供map任務處理)或該檔案的一部分(檔案大,被分割槽)。
3.3、常用的InputFormat實現
小檔案與CombineFileInputFormat
雖然hadoop適合處理大檔案,但在實際的情況中,大量的小檔案處理是少不了的,因此hadoop提供了一個CombineFileInputFormat,它針對小檔案而設計的,它把多個檔案打包到一個分片中一般每個mapper可以處理更多的資料。
TextInputFormat
hadoop預設的InputFormat,每個記錄的鍵是檔案中行的偏移量,值為行內容。
KeyValueInputFormat
適合處理配置檔案,檔案中行中為key value格式的,如key=value型別的檔案 ,key即為行中的key,value即為行中的value。
NLineInputFormat
也是為處理文字檔案而開發的,它的特點是為每個map任務收到固定行數的輸入,其他與TextInputFormat相似。
SequenceFileInputFormat(二進位制輸入)
hadoop的順序檔案格式儲存格式儲存二進位制的鍵值對序列,由於順序檔案裡面儲存的就是map結構的資料,所以剛好可以有SequenceFileInputFormat 來進行處理。
DBInputFormat
顧名思義,用於使用jdbc從關聯式資料庫中讀取資料。
多種輸入
MultipleInputs類可以用來處理多種輸入格式的資料,如輸入資料中包含文字型別和二進位制型別的,這個時候就可以用 MultipleInputs來指定某個檔案有哪種輸入型別和哪個map函式來解析。
3.4、輸出格式
既然有輸入格式,就有輸出格式,與輸入格式對應。
預設的輸出格式是TextOutputFormat,它把記錄寫成文字行,鍵值對可以是任意型別, 鍵值對中間預設用製表符分割。
3.5、hadoop特性
除了上面幾點之外,還有計數器、排序、連線等需要關注,詳細待後續吧。。。
相關文章
- Hadoop 三劍客之 —— 分散式計算框架 MapReduceHadoop分散式框架
- Hadoop大資料實戰系列文章之Mapreduce 計算框架Hadoop大資料框架
- 大資料時代之hadoop(四):hadoop 分散式檔案系統(HDFS)大資料Hadoop分散式
- Titan-hadoop 分散式圖計算框架Hadoop分散式框架
- 大資料時代之hadoop(一):hadoop安裝大資料Hadoop
- 大資料之Hadoop偽分散式的搭建大資料Hadoop分散式
- 大資料時代之hadoop(二):hadoop指令碼解析大資料Hadoop指令碼
- Hadoop 分散式儲存分散式計算Hadoop分散式
- 大資料系列分享第四期:《MapReduce分散式計算框架》大資料分散式框架
- 大資料時代之hadoop(三):hadoop資料流(生命週期)大資料Hadoop
- Hadoop偽分散式安裝(MapReduce+Yarn)Hadoop分散式Yarn
- Hadoop-MapReduce-TeraSort-大資料排序例子Hadoop大資料排序
- Hadoop-MapReduce之自定義資料型別Hadoop資料型別
- 淺析大資料框架 Hadoop大資料框架Hadoop
- Hadoop MapReduce之wordcount(詞頻統計)Hadoop
- Hadoop面試題之MapReduceHadoop面試題
- Hadoop元件--分散式資料庫HbaseHadoop元件分散式資料庫
- 使用hadoop mapreduce分析mongodb資料HadoopMongoDB
- 雲端計算課程實驗之安裝Hadoop及配置偽分散式模式的HadoopHadoop分散式模式
- Hadoop大資料分散式處理系統簡介Hadoop大資料分散式
- 大資料2-Hadoop偽分散式+ZK+HDFS大資料Hadoop分散式
- 分散式計算技術(上):經典計算框架MapReduce、Spark 解析分散式框架Spark
- Hadoop 新 MapReduce 框架 Yarn 詳解Hadoop框架Yarn
- 大資料時代之hadoop(六):hadoop 生態圈(pig,hive,hbase,ZooKeeper,Sqoop)大資料HadoopHive
- 大資料技術之Hadoop(入門) 第2章 從Hadoop框架討論大資料生態大資料Hadoop框架
- 好程式設計師大資料培訓分享Hadoop分散式叢集程式設計師大資料Hadoop分散式
- Hadoop之MapReduce2架構設計Hadoop架構
- hadoop學習之hadoop完全分散式叢集安裝Hadoop分散式
- hadoop 之distcp(分散式拷貝)HadoopTCP分散式
- Hadoop(十九)MapReduce OutputFormat 資料壓縮HadoopORM
- 小白學習大資料測試之hadoop hdfs和MapReduce小實戰大資料Hadoop
- hadoop&spark mapreduce對比 & 框架設計和理解HadoopSpark框架
- CG_Hadoop:基於MapReduce的計算幾何Hadoop
- Hadoop入門(一)之Hadoop偽分散式環境搭建Hadoop分散式
- 大資料計算的基石——MapReduce大資料
- Hadoop MapReduce進階 使用分散式快取進行replicated joinHadoop分散式快取
- Hadoop大資料開發框架學習Hadoop大資料框架
- MapReduce&&HadoopHadoop