mapreduce的功能主要來自于它的簡單性。除了準備輸入數據之外,程序員只需要操作mapper和reducer。現實中的很多問題都可以利用這種方法解決。
在大多數情況下, MapReduce可以作為一個通用的并行執行框架,充分利用數據的本地性。但是這種簡單性是有代價的,設計者必須從以特定的方式組合在一起的一小部分組件的角度決定如何表達他的業務問題。
重新制定MapReduce的初始問題,通常有必要回答以下問題:
1. 怎么把一個大問題分解成多個小任務?更具體地說,你怎么分解問題以至于這些小任務可以并行執行?
2.你會選擇哪對key/value作為每個任務的輸出/輸出?
3. 你如何匯總計算所需要的所有數據?更具體地說, 你怎么安排處理的方式,使所有必要的計算中的數據都同時在內存中?
我們要認識到,很多算法不能很容易地表示為一個單一的MapReduce作業。它往往需要把復雜的算法分解成一系列的作業,把其中一個作業的數據輸出成為下一個作業的輸入。
本節將會探討在幾個設計不同的實際MapReduce應用問題的例子(從簡單到復雜)。所有的例子都會被描述為以下形式:
1.Mapper的描述
2.Reducer的描述
這種情況下的mapreduce實施是非常簡單的――唯一需要的就是mapper,單獨的處理每個記錄然后輸出結果。在這個例子中,Mapreduce控制mappers的分布,提供調度和錯誤處理的所有支持。下面的例子展示了如何設計這種類型的應用程序。
雖然不是經常作為Hadoop-related問題討論,但是圖像處理應用在mapreduce范例中是非常合適的。假設有一個人臉識別算法的應用,需要一個圖像,識別一系列想要的特性,并產生一組識別結果。再假設需要在百萬圖片上做人臉識別。如果所有的圖片以序列文件的形式存放在hadoop中,那么你可以用一個簡單的map作業就可以實現并行處理。在這個例子中,輸入的key/value是ImageID/Image,輸出的key/value是ImageID/可特征識別列表。此外,一組可特征識別必須分布到所有的mapper(例如,利用分布式緩存)。
人臉識別作業
Mapper | 在這個作業中,mapper首先以可識別特征集進行初始化,對于每一個圖像,一個map函數通過它的圖像本身,以及可識別的列表來調用的人臉識別算法。識別的結果連同原來imageID一起從map中輸出。 |
Result | 這個作業執行的結果是所有包含在原始圖片中識別出來的圖片。 |
注意:要實現完全獨立的mappers/reducers。在mapreduce應用中的每一個mapper/reducer需要創建獨自的輸出文件。這意味著,人臉識別的作業的執行結果將是一組文件(相同目錄下的),每一個包含了各自mapper的輸出。如果需要把他們放入到一個單個的文件中。必須在人臉識別作業中添加一個單獨的reducer。這個reducer是非常簡單的。因為在這個例子中,每一個作為reduce的輸入的key只有一個單獨的value(這里假設圖像的ID是唯一的),reducer只是把輸入的key/value直接寫入到輸出文件。我們要知道在這個例子中盡管一個reducer極其簡單,但是這種額外的作業明顯的增加了作業的整體運行時間。這是因為額外的reducer分為shuffle和sort(不單單在map作業中出現),當圖像的數量非常大時,將花費大量的時間。
這種情況的一個例子就是構建倒排索引。這種類型的問題需要所有的mapreduce步驟進行執行,需要shuffle和sort把所有的結果集合在一起。下面的例子展示了如何設計這種類型的應用。
在計算機科學中,倒排索引是一個數據框架,用來存放了從內容(例如單詞或者數字)到它在一個文檔或一組文檔里的位置的映射,如表3-6所示。倒排索引的目的是實現快速的全文搜索,在文檔增加的時候增加處理成本為代價,倒排索引式的數據結構是典型搜索引擎的關鍵部分,優化了查找某些單詞出現的文檔的速度。
文檔 | ||
ID | Title | Content |
1 | Popular | Football is Popular in US |
2 | Common Sport | Soccer is commonly played in Europe |
3 | National Sport | Cricket is played all over India |
… | … | … |
表2-1:文檔結構
倒排索引 | ||||
Term | value | Document | Document | Document |
Title | popular | 1 | ||
Title | sport | 1 | 2 | 3 |
Title | common | 2 | ||
Title | national | 3 | ||
Content | football | 1 | ||
Content | is | 1 | 2 | 3 |
Content | popular | 1 | ||
… | … | … | … | … |
表2-2:倒排索引
要創建倒排索引,可以把每個文檔(或者文檔里行)給mapper。mapper可以解析出文檔里的多個單詞,然后輸出[單詞,詞頻]鍵值對。reducer可以只是一個識別,輸出列表或者可以執行每個單詞的一些統計匯總的功能。
注釋在第九章你將學會更多關于如何利用Hbase來存儲倒排的索引。
表2-3里展示了這個例子中mapreduce作業的實現。
表2-3 倒排索引的計算
處理階段 | 描述 |
Mapper | 作業中,mapper的任務是構建一個包含一個單詞索引的獨特的記錄和描述在文檔里單詞出現的信息。它讀取每個輸入的文檔,解析,然后為文檔里的每一個獨特的單詞創建一個索引描述符。該描述符包含文檔的ID,文檔里索引出現的次數,和任何附件的信息(比如從文檔的開頭索引位置的偏移量) ,每一個所以描述符被寫出。 |
Shuffle和sort | Mapreduce的shuffle和sort過程會把所有的記錄都按照索引值排序,確保reducer接受到所有相同key值的索引。 |
Reducer | 這項工作中,reducer的作用是構建一個倒排索引結構。根據系統的要求,可能有一個或多個reducer。Reducer得到所有給定索引的描述符,并生成一個索引記錄,并寫入到指定的索引存儲。 |
Result | 該作業執行的結果是一組原始文檔的倒排索引。 |
表2-3:倒排索引的計算
更多復雜的mapreduce應用需要將來自多個獲取的數據(就是說連接數據)進行處理。
什么場景下用MapReduce
為了能使Mapreduce可以應用,下面必須符合:
1、? 要運行的計算必須可以組合,它指的是必須能對數據集下的小數據集進行計算。然后對部分結果合并。
2、? 數據集的大小要足夠大(或者計算時間要足夠長),當基礎設施? 為獨立的計算和合并結果不會對整體性能造成影響。
3、? 計算主要取決于于正在處理的數據集。用Hbase可以額外添加小的數據集。分布式緩存或者一些其他的技術。
然而,當數據集必須能隨機的被訪問去執行操作(例如,如果一個給定的數據集記錄必須加上額外的記錄來執行操作),在這種情境中,mapreduce是不適用的。然后在這種情況下,可以運行額外的mapreduce作業來為計算“準備”數據。
另外一些不適用mapreduce的問題是遞歸問題(例如,斐波那契問題)。在這種情況下,mapreduce不適用是因為當前value值的計算需要前一個的知識。這就意味著你不能把它們分解成為可以單獨運行的子計算(sub computation)。
如果一個數據足夠的小,小到可以放到一個機器的內存里,作為一個獨立的應用程序可能會處理的更快。在這種情況下,使用mapreduce,會使執行變得不必要的復雜,通常會更慢。
注意,(keep it in mind),雖然一大類的算法不能直接應用在mapreduce的實施上。但是對于同樣的基本問題,往往存在可以通過利用mapreduce解決的替代解決方案。這種情況下,使用mapreduce通常是有利的,因為mapreduce是在有豐富的hadoop生態系統中執行的(支持更容易的改進的實施),并與其它應用程序的集成。
最后 你應該記住Mapreduce本質上是一個批處理實現。決不能用于在線計算(比如在線用戶請求的實時計算)。
當你設計mapreduce應用的時候,下面列舉的是需要注意和避免的。
1、? 擁有過多的mapper會造成調度和基礎設施的開銷,在極端情況下,甚至會殺死一個Jobtracker。另外,過多的mapper通常會提高整體資源的利用率(因為創建過多的JVM)和執行時間(因為執行slot的數量是有限的)。
2、? Mapper太少會導致集群不能充分利用,給一些節點(實現運行mapper的節點)造成過度負載。此外,在有大型map任務情況下,重試和推測執行的情況會變得非常昂貴的代價且會花費更長的時間。
3、? 大量小型的mapper會造成大量的尋求,shuffle map輸出給reducer的結果時。當把map的輸出結果傳遞給reducer時,它也會造成過多的連接。
1、? 除了調度和基礎設施的開銷外,大量的reducer會創建太多的輸出文件(記住,每個reducer創建自己的輸出文件),對namenode有負面的影響。當有其他作業利用該mapreduce作業的結果時,它會變得更為復雜。
2、? 太少的reducer和太少的mapper一樣,造成同樣的負面影響-不能充分利用集群和非常昂貴(代價)的回調。(retry)
1、? 計數器在跟蹤少量的,重要的,全局的信息是適用的(在Chapter 5了解更多關于使用計數器的詳情)。他們絕對不是只是整合非常細粒度統計的應用程序。
2、? 計數器的代價非常高,因為Jobtracker在應用程序的整個持續時間內,必須維持每個map/reduce任務的每一個計數器。
1、? 盡量避免在map和reduce方法中添加新的類的實例。這些方法在執行過程中會循環執行多次。也就是說類的創建和處理將增加執行的時間,為垃圾收集器增加額外的工作。比較好的方法是在相應的set()方法中創建大量的中間類,然后重寫map和reduce方法。
2、? 不要用分布式緩存來移動大數量的工件或者非常大的工件(每個百兆字節)。分布式緩存的設計是用來分布小部分中等大小的工件,幾兆到幾十兆大小。
3、? 處理少量的數據時,不要創建成百上千個小作業式的工作流。
4、? 不直接從reducer或者mapper直接寫入用戶自定義的文件。Hadoop中當前實現文件寫的功能是單線程的,這意味著當多個mapper/reducer試圖寫文件時,這個執行將被序列化。
5、? 不要創建這樣的mapreduce功能,掃描一個Hbase表來創建一個新的Hbase表(或者寫入同樣的表中)? 。TableInputFormat是為基于具有時間敏感性的表掃描的Hbase和Mapreduce的實現。? 另一方面,Hbase寫功能會因為Hbase表的分割而產生一定的寫延遲。 結果是Region服務器會掛掉,然后你會失去一些數據。最好的解決方案是把作業分割成兩個作業。一個掃描表并想HDFS中寫入中間結果。另一個從HDFS讀取數據并寫入到HBase中。
來自:
原文地址:MR總結(二)-Mapreduce程序設計, 感謝原作者分享。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com