map/reduce 過程的認識

 map/reduce 過程的認識

 

      最初我一直簡單的以爲map的工作就是將數據打散,而reduce就是將map打散後的數據合併。雖然之前跑過wordcount的例子,但之前只是對輸出reduce最終的結果感興趣,對控制檯打印的日誌信息完全不懂。這幾天我們團隊在探索pagerank,纔開始對map/reduce有了深一層的瞭解。當一個job提交後,後續具體的一系列分配調度工作我現在不清楚。我現在只是瞭解些map/reduce過程。

 原來map過程和reduce的過程也都包含了多個步驟。

 

         一.  Map 階段

  作業的inputFormat類規定了對提交的作業的輸入文件切分方法。默認是將輸入文件按照字節的大小分割成不同的塊。 至於這個過程到底是怎麼實現的我也不清楚。我現在只是記錄下我對map reduce的理解。

 

  輸入文件可能會被打散成多個塊(block),至於是怎麼分成塊的,我不清楚。一個塊的大小是默認是64MB,也是可以通過參數設置的其大小的。所以若採用默認的,如果初始數據<64MB 時,就只有一個塊了。每一個塊就是一個Map task的輸入。也就是說有多少個塊就會有多少個map task。 那map task 的工作是怎麼樣的呢?

   

 

    簡單的來說,map task 也有幾個步驟:從hdfs上獲取block數據à從內存中溢寫(spill)文件àmerge溢寫文件

           1.   block和map task怎麼聯繫起來的呢。那些任務都是屬於作業提交後的初始化和調度問題了。我還沒有明白。第一步就先不說了,只能簡單的理解是map task知道它的輸入數據(block)在哪裏,直接去取就可以了。

 

在DataNode節點上的每個map task任務都會有一個內存緩衝區,用來臨時存儲它的輸出結果的,其實也就是減少對磁盤的讀寫頻率。這裏面的數據只是key/value對和partition的結果。前者我們都可以理解是什麼東西,那後者呢?我們都知道map task的數量不是完全由人爲設置的,但reduce task的數目是client設置的,默認是1。這就需要對key值劃分區,知道哪些key 是由哪個reduce task處理的。Partitioner就是幹這個工作的。默認的方法是使用Hash函數,當然用戶也可以通過實現自定義的 Partitioner來控制哪個key被分配給哪個 Reducer。結果可能會出現多個key/value對最終交由同一個reduce task去處理。針對這些key/value對就需要合併了,合併是爲了減小map最終文件在磁盤上的溢寫。至於這個合併到底是在哪個時期進行的,我也不清楚。

 

          2.  當然這個緩衝區也是有大小限制的(默認是100MB)。我們也可以通過某些屬性來設置這個具體大小。而如果Map的輸出結果很大,緩衝區容納不了時,必定要適時將緩衝區的數據寫在磁盤上(也稱爲spill過程)。默認爲緩衝區的容量達到80%時(當然可以去重新設置了),就將它寫入磁盤。如果等到緩衝區滿纔開始這部分的工作,那在寫入磁盤的過程中,map可能還要輸出數據,因爲那個溢寫的過程是由單獨的線程控制的。那麼是否有可能會出現內存溢出?爲了避免這種情況,這就需要前面所說的那個80%的門限值了。而在這個溢寫過程也會對這些數據進行sort,默認是使用快速排序對key和partition做排序。這些數據記錄本身是以什麼格式存儲在內存中的我還不清楚,所以也不明白到底是如何個快速排序法。

 

 

          3.  每次spill過程寫入磁盤的數據是生成一個單獨文件的(通常稱爲溢寫文件),這就又會出現Map真正執行完成後,如果是大數據量結果輸出,則會形成很多個溢寫文件。那麼勢必又要將這些個文件合併到一起。這個過程就稱爲merge 了。至於每次merge的溢寫文件數目是可以通過參數設置的,但是我不知道是不是總的merge次數是否也有限定,我現在還不清楚。

 

但是可能又會有疑問了,如果merge只是簡單的合併過程,那如果像wordcount例子的情況,假如第一個溢寫文件中單詞“hello”(key值) 出現的次數是4(value值),第二個溢寫文件中 單詞“hello”(key值) 出現的次數是9(value值),假設只有兩個溢寫文件。那merge後還是會出現相同的key值鍵對。所以如果之前設置過combiner ,此就會使用combiner將相同的key的values合併,形成 hello(key值)---[4,9](values值)。 這個combine過程並不一定要等到merge結束後才執行,而且也並不是一定要執行,用戶可以自己設置的。 當這些個步驟都結束後map端的工作 纔算結束。最終的這個輸出文件也是存儲在本地磁盤中的。

 

 

               二. Reduce階段

Reduce是將map 的輸出結果作爲它的輸入文件。整個reduce過程就又涉及到多個步驟了。Reduce過程並不是要等到所有的map task執行完後才執行。只要有一個map task執行完後,reduce階段就可以開始了。

       這個過程我只能用粗略圖表示了。

 

 

 

             1.  首先就是怎麼得到map的輸出數據。在實際運行過程中map的運行過程很可能和reduce的運行過程不在同一個節點(datanode)上。那它們之間到底是怎麼聯繫的呢?它是通過HTTP方式請求Jobtracker獲取當前有哪些 map task任務已完成,然後從map task所在的TaskTracker遠程獲取map task的輸出文件。但並不是map的整個輸出文件,而只是獲取由該reduce task處理的那部分數據就可以了。

 

               2.  在這個下載過程中,它也會一邊做歸併排序,因爲不同的Map結果中可能會有相同的key值。爲什麼是採用歸併呢?不懂!如果之前設置了combine,此時也會做這個工作。而對一個reduce來說,它的數據可能是多個map 上的數據,而它的下載過程可以是並行的,不過這個並行的數目是可以設置的,默認是5。也就是說,即使reduce 所需要的數據是從很多個map上的(若是大於設置的並行度),也只能一次並行的從設置的這麼多個Map上下載所需數據。

         我想不通的是這樣會不會太麻煩了點啊,多浪費網絡資源啊。不過,我也不知道它們之間該使用什麼樣的數據傳輸會更好。

 

              3.  copy獲取到的數據首先也是放入到內存中的,也就是說這裏又出現了類似map階段中的溢寫過程了,會產生溢寫文件。所以在這裏就又有了merge的過程了。使得最終形成一個文件。不過這個文件有可能是在內存中,也有可能是在磁盤上了,默認是在磁盤上的。當最終文件形成後,reduce 函數纔開始執行。並將最終的結果寫到hdfs上,至於這步是如何寫上去的,還不清楚。至此整個reduce 階段纔算結束。在這裏還有明白的就是reduce後的結果並不是排序好的,而map 的最終數據是已經排好序的,且已經是分好區的了。

 

     三.  最後還有需要說明的是client可以控制對這些中間結果是否進行壓縮以及怎麼壓縮,使用哪種壓縮格式。也不是說一定要這個壓縮步驟,若需要寫入磁盤的數據量太大,相對來說就可以讓CPU幫忙減輕下IO負荷。具體map reduce整個過程中有太多問題還不清楚,還要繼續驗證。總之就是越發覺得複雜了。


文章來自:http://linglxia.iteye.com/blog/1396630

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章