Hadoop之 MapReducer工作過程
一個MapReducer作業經過了input,map,combine,reduce,output五個階段,其中combine階段並不一定發生,map輸出的中間結果被分到reduce的過程成為shuffle(資料清洗)。
在shuffle階段還會發生copy(複製)和sort(排序)。
在MapReduce的過程中,一個作業被分成Map和Reducer兩個計算階段,它們由一個或者多個Map任務和Reduce任務組成。如下圖所示,一個MapReduce作業從資料的流向可以分為Map任務和Reduce任務。當使用者向Hadoop提交一個MapReduce作業時,JobTracker則會根據各個TaskTracker週期性傳送過來的心跳資訊綜合考慮TaskTracker的資源剩餘量,作業優先順序,作業提交時間等因素,為TaskTracker分配合適的任務。Reduce任務預設會在Map任務數量完成5%後才開始啟動。
Map任務的執行過程可以概括為:首先透過使用者指定的InputFormat類中的getSplits方法和next方法將輸入檔案切片並解析成鍵值對作為map函式的輸入。然後map函式經過處理之後將中間結果交給指定的Partitioner處理,確保中間結果分發到指定的Reduce任務處理,此時如果使用者指定了Combiner,將執行combine操作。最後map函式將中間結果儲存到本地。
Reduce任務的執行過程可以概括為:首先需要將已經完成Map任務的中間結果複製到Reduce任務所在的節點,待資料複製完成後,再以key進行排序,透過排序,將所有key相同的資料交給reduce函式處理,處理完成後,結果直接輸出到HDFS上。
2. input如果使用HDFS上的檔案作為MapReduce的輸入,MapReduce計算框架首先會用org.apache.hadoop.mapreduce.InputFomat類的子類FileInputFormat類將作為輸入HDFS上的檔案切分形成輸入分片(InputSplit),每個InputSplit將作為一個Map任務的輸入,再將InputSplit解析為鍵值對。InputSplit的大小和數量對於MaoReduce作業的效能有非常大的影響。
InputSplit只是邏輯上對輸入資料進行分片,並不會將檔案在磁碟上分成分片進行儲存。InputSplit只是記錄了分片的後設資料節點資訊,例如起始位置,長度以及所在的節點列表等。資料切分的演算法需要確定InputSplit的個數,對於HDFS上的檔案,FileInputFormat類使用computeSplitSize方法計算出InputSplit的大小,程式碼如下:
- protected long computeSplitSize(long blockSize, long minSize, long maxSize) {
- return Math.max(minSize, Math.min(maxSize, blockSize));
- }
其中 minSize 由mapred-site.xml檔案中的配置項mapred.min.split.size決定,預設為1;maxSize 由mapred-site.xml檔案中的配置項mapred.max.split.size決定,預設為9223 372 036 854 775 807;而blockSize是由hdfs-site.xml檔案中的配置項dfs.block.size決定,預設為67 108 864位元組(64M)。所以InputSplit的大小確定公式為:
- max(mapred.min.split.size, min(mapred.max.split.size, dfs.block.size));
一般來說,dfs.block.size的大小是確定不變的,所以得到目標InputSplit大小,只需改變mapred.min.split.size 和 mapred.max.split.size 的大小即可。InputSplit的數量為檔案大小除以InputSplitSize。InputSplit的原資料資訊會透過一下程式碼取得:
- splits.add(new FileSplit(path, length - bytesRemaining, splitSize, blkLocations[blkIndex].getHosts()));
從上面的程式碼可以發現,後設資料的資訊由四部分組成:檔案路徑,檔案開始位置,檔案結束位置,資料塊所在的host。
對於Map任務來說,處理的單位為一個InputSplit。而InputSplit是一個邏輯概念,InputSplit所包含的資料是仍然儲存在HDFS的塊裡面,它們之間的關係如下圖所示:
當輸入檔案切分為InputSplit後,由FileInputFormat的子類(如TextInputFormat)的createRecordReader方法將InputSplit解析為鍵值對,程式碼如下:
- public RecordReader<LongWritable, Text>
- createRecordReader(InputSplit split,
- TaskAttemptContext context) {
- String delimiter = context.getConfiguration().get(
- "textinputformat.record.delimiter");
- byte[] recordDelimiterBytes = null;
- if (null != delimiter)
- recordDelimiterBytes = delimiter.getBytes(Charsets.UTF_8);
- return new LineRecordReader(recordDelimiterBytes);
- }
此處預設是將行號作為鍵。解析出來的鍵值對將被用來作為map函式的輸入。至此input階段結束。
3. map及中間結果的輸出InputSplit將解析好的鍵值對交給使用者編寫的map函式處理,處理後的中間結果會寫到本地磁碟上,在刷寫磁碟的過程中,還做了partition(分割槽)和 sort(排序)的操作。
map函式產生輸出時,並不是簡單的刷寫磁碟。為了保證I/O效率,採取了先寫到記憶體的環形記憶體緩衝區,並做一次預排序,如下圖所示:
每個Map任務都有一個環形記憶體緩衝區,用於儲存map函式的輸出。預設情況下,緩衝區大小是100M,該值可以透過mapred-site.xml檔案中的io.sort.mb的配置項配置。一旦緩衝區內容達到閾值(由mapred-site.xml檔案的io.sort.spill.percent的值決定,預設為0.80 或者 80%),一個後臺執行緒便會將緩衝區的內容溢寫到磁碟中。再寫磁碟的過程中,map函式的輸出繼續被寫到緩衝區,但如果在此期間緩衝區被填滿,map會阻塞直到寫磁碟過程完成。寫磁碟會以輪詢的方式寫到mapred.local.dir(mapred-site.xml檔案的配置項)配置的作業特定目錄下。
在寫磁碟之前,執行緒會根據資料最終要傳入到的Reducer把緩衝區的資料劃分成(預設是按照鍵)相應的分割槽。在每個分割槽中,後臺執行緒按照建進行內排序,此時如果有一個Combiner,它會在排序後的輸出上執行。
一旦記憶體緩衝區達到溢位的閾值,就會新建一個溢位寫檔案,因此在Map任務完成最後一個輸出記錄之後,會有若干個溢位寫檔案。在Map任務完成之前,溢位寫檔案被合併成一個已分割槽且已排序的輸出檔案作為map輸出的中間結果,這也是Map任務的輸出結果。
如果已經指定Combiner且溢位寫次數至少為3時,Combiner就會在輸出檔案寫到磁碟之前執行。如前文所述,Combiner可以多次執行,並不影響輸出結果。執行Combiner的意義在於使map輸出的中間結果更緊湊,使得寫到本地磁碟和傳給Reducer的資料更少。
為了提高磁碟IO效能,可以考慮壓縮map的輸出,這樣會寫磁碟的速度更快,節約磁碟空間,從而使傳送給Reducer的資料量減少。預設情況下,map的輸出是不壓縮的,但只要將mapred-site.xml檔案的配置項mapred.compress.map.output設為true即可開啟壓縮功能。使用的壓縮庫由mapred-site.xml檔案的配置項mapred.map.output.compression.codec
指定,如下列出了目前hadoop支援的壓縮格式:
壓縮格式 | 工具 | 演算法 | 副檔名 | 是否包含多個檔案 | 是否可切分 |
---|---|---|---|---|---|
DEFLATE* | N/A | DEFLATE | .deflate | 否 | 否 |
Gzip | gzip | DEFLATE | .gz | 否 | 否 |
bzip2 | bzip2 | bzip2 | .bz2 | 否 | 是 |
LZO | Lzop | LZO | .lzo | 否 | 否 |
map輸出的中間結果儲存的格式為IFile,IFile是一種支援航壓縮的儲存格式,支援上述壓縮演算法。
Reducer透過Http方式得到輸出檔案的分割槽。將map輸出的中間結果傳送到Reducer的工作執行緒的數量由mapred-site.xml檔案的tasktracker.http.threds配置項決定,此配置針對每個節點,而不是每個Map任務,預設是40,可以根據作業大小,叢集規模以及節點的計算能力而增大。
4. shuffleshuffle,也叫資料清洗。在某些語境下,代表map函式產生輸出到reduce的消化輸入的整個過程。
4.1 copy階段Map任務輸出的結果位於Map任務的TaskTracker所在的節點的本地磁碟上。TaskTracker需要為這些分割槽檔案(map輸出)執行Reduce任務。但是,Reduce任務可能需要多個Map任務的輸出作為其特殊的分割槽檔案。每個Map任務的完成時間可能不同,當只要有一個任務完成,Reduce任務就開始複製其輸出。這就是shuffle的copy階段。如下圖所示,Reduce任務有少量複製執行緒,可以並行取得Map任務的輸出,預設值為5個執行緒,該值可以透過設定mapred-site.xml的mapred.reduce.parallel.copies的配置項來改變。
如果map輸出相當小,則會被複制到Reduce所在TaskTracker的記憶體的緩衝區中,緩衝區的大小由mapred-site.xml檔案中的mapred.job.shuffle.input.buffer.percent配置項指定。否則,map輸出將會被複制到磁碟。一旦記憶體緩衝區達到閾值大小(由mapred-site.xml檔案mapred.job.shuffle.merge.percent配置項決定)或緩衝區的檔案數達到閾值大小(由mapred-site.xml檔案mapred.inmem.merge.threshold配置項決定),則合併後溢寫到磁碟中。
4.2 sort階段隨著溢寫到磁碟的檔案增多,shuffle進行sort階段。這個階段將合併map的輸出檔案,並維持其順序排序,其實做的是歸併排序。排序的過程是迴圈進行,如果有50個map的輸出檔案,而合併因子(由mapred-site.xml檔案的io.sort.factor配置項決定,預設為10)為10,合併操作將進行5次,每次將10個檔案合併成一個檔案,最後有5個檔案,這5個檔案由於不滿足合併條件(檔案數小於合併因子),則不會進行合併,將會直接把5個檔案交給Reduce函式處理。到此shuffle階段完成。
從shuffle的過程可以看出,Map任務處理的是一個InputSplit,而Reduce任務處理的是所有Map任務同一個分割槽的中間結果。
5. reduce及最後結果的輸出reduce階段操作的實質就是對經過shuffle處理後的檔案呼叫reduce函式處理。由於經過了shuffle的處理,檔案都是按鍵分割槽且有序,對相同分割槽的檔案呼叫一次reduce函式處理。
與map的中間結果不同的是,reduce的輸出一般為HDFS。
6. sort排序貫穿於Map任務和Reduce任務,排序操作屬於MapReduce計算框架的預設行為,不管流程是否需要,都會進行排序。在MapReduce計算框架中,主要用到了兩種排序演算法:快速排序和歸併排序。
在Map任務和Reduce任務的過程中,一共發生了3次排序操作。
(1)當map函式產生輸出時,會首先寫入記憶體的環形緩衝區,當達到設定的閾值,在刷寫磁碟之前,後臺執行緒會將緩衝區的資料劃分相應的分割槽。在每個分割槽中,後臺執行緒按鍵進行內排序。如下圖所示。
(2)在Map任務完成之前,磁碟上存在多個已經分好區,並排好序,大小和緩衝區一樣的溢寫檔案,這時溢寫檔案將被合併成一個已分割槽且已排序的輸出檔案。由於溢寫檔案已經經過一次排序,所以合併檔案時只需再做一次排序就可使輸出檔案整體有序。如下圖所示。
(3)在shuffle階段,需要將多個Map任務的輸出檔案合併,由於經過第二次排序,所以合併檔案時只需在做一次排序就可以使輸出檔案整體有序。
在這3次排序中第一次是在記憶體緩衝區做的內排序,使用的演算法是快速排序;第二次排序和第三次排序都是在檔案合併階段發生的,使用的是歸併排序。
7. 作業的進度組成一個MapReduce作業在Hadoop上執行時,客戶端的螢幕通常會列印作業日誌,如下:
對於一個大型的MapReduce作業來說,執行時間可能會比較比較長,透過日誌瞭解作業的執行狀態和作業進度是非常重要的。對於Map來說,進度代表實際處理輸入所佔比例,例如 map 60% reduce 0% 表示Map任務已經處理了作業輸入檔案的60%,而Reduce任務還沒有開始。而對於Reduce的進度來說,情況比較複雜,從前面得知,reduce階段分為copy,sort 和 reduce,這三個步驟共同組成了reduce的進度,各佔1/3。如果reduce已經處理了2/3的輸入,那麼整個reduce的進度應該為1/3 + 1/3 + 1/3 * (2/3) = 5/9 ,因為reduce開始處理時,copy和sort已經完成。
來源於:《Hadoop 海量資料處理》
轉: http://blog.csdn.net/sunnyyoona/article/details/53939546
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31383567/viewspace-2150854/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 高可用Hadoop平臺-Oozie工作流之Hadoop排程Hadoop
- hadoop Kerberos過程HadoopROS
- OAuth 2.0以及它的工作過程工作過程OAuth
- hadoop之旅6-windows本地MapReducer離線單詞統計HadoopWindows
- hadoop支援lzo完整過程Hadoop
- DMA的工作過程
- CDN基本工作過程 (轉)
- [譯] Redux 的工作過程Redux
- Hadoop之hive安裝過程以及執行常見問題HadoopHive
- 編譯器的工作過程編譯
- oracle的undo的工作過程Oracle
- Hadoop2.3.0詳細安裝過程Hadoop
- FreeBSD DHCP的工作過程(轉)
- [個體軟體過程]之過程改進 (轉)
- 談談 ajax 工作過程那點事
- 編譯器的工作過程和原理編譯
- Activiti配置工作流結束過程
- Hadoop過程中配置SSH免密碼登入Hadoop密碼
- 搭建yarn(hadoop-2.2.0)環境詳細過程YarnHadoop
- Hadoop學習第四天--MapReduce提交過程Hadoop
- MySQL之儲存過程MySql儲存過程
- MapReducer中的多次歸約處理
- python中try語句的工作過程Python
- 【Android原始碼】BroadcastReceiver的工作過程Android原始碼AST
- 【DSL】Elasticsearch之Analyze(分析過程)Elasticsearch
- MyBatis 示例之儲存過程MyBatis儲存過程
- Hadoop1.x MapReduce 程式執行的詳細過程Hadoop
- Hadoop平臺學習過程的一些總結Hadoop
- AIX 使用者工作環境建立的過程AI
- Oracle Pl/SQL 之 儲存過程OracleSQL儲存過程
- hadoop之 hadoop用途方向Hadoop
- Hadoop原始碼:namenode格式化和啟動過程實現Hadoop原始碼
- 詳解NTP網路時間協議工作過程協議
- 從巨集觀的角度看 Gradle 的工作過程Gradle
- pt-online-schema-change工作過程介紹
- oracle資料庫服務的工作過程與原理Oracle資料庫
- WiFi基礎(四):WiFi工作原理及WiFi接入過程WiFi
- 雲端計算課程實驗之安裝Hadoop及配置偽分散式模式的HadoopHadoop分散式模式