MapReduce原理與設計思想

簡單解釋 MapReduce 算法

一個有趣的例子

你想數出一摞牌中有多少張黑桃。直觀方式是一張一張檢查並且數出有多少張是黑桃?

MapReduce方法則是:

  1. 給在座的所有玩家中分配這摞牌

  2. 讓每個玩家數自己手中的牌有幾張是黑桃,然後把這個數目彙報給你

  3. 你把所有玩家告訴你的數字加起來,得到最後的結論

拆分

MapReduce合併了兩種經典函數:

  • 映射(Mapping)對集合裏的每個目標應用同一個操作。即,如果你想把表單裏每個單元格乘以二,那麼把這個函數單獨地應用在每個單元格上的操作就屬於mapping。

  • 化簡(Reducing )遍歷集合中的元素來返回一個綜合的結果。即,輸出表單裏一列數字的和這個任務屬於reducing。

重新審視上面的例子

重新審視我們原來那個分散紙牌的例子,我們有MapReduce數據分析的基本方法。友情提示:這不是個嚴謹的例子。在這個例子裏,人代表計算機,因爲他們同時工作,所以他們是個集羣。在大多數實際應用中,我們假設數據已經在每臺計算機上了 – 也就是說把牌分發出去並不是MapReduce的一步。(事實上,在計算機集羣中如何存儲文件是Hadoop的真正核心。)

通過把牌分給多個玩家並且讓他們各自數數,你就在並行執行運算,因爲每個玩家都在同時計數。這同時把這項工作變成了分佈式的,因爲多個不同的人在解決同一個問題的過程中並不需要知道他們的鄰居在幹什麼。

通過告訴每個人去數數,你對一項檢查每張牌的任務進行了映射。 你不會讓他們把黑桃牌遞給你,而是讓他們把你想要的東西化簡爲一個數字。

另外一個有意思的情況是牌分配得有多均勻。MapReduce假設數據是洗過的shuffled)- 如果所有黑桃都分到了一個人手上,那他數牌的過程可能比其他人要慢很多。

如果有足夠的人的話,問一些更有趣的問題就相當簡單了 - 比如“一摞牌的平均值(二十一點算法)是什麼”。你可以通過合併“所有牌的值的和是什麼”及“我們有多少張牌”這兩個問題來得到答案。用這個和除以牌的張數就得到了平均值。

MapReduce算法的機制要遠比這複雜得多,但是主體思想是一致的 – 通過分散計算來分析大量數據。無論是Facebook、NASA,還是小創業公司,MapReduce都是目前分析互聯網級別數據的主流方法。

本文地址:http://www.cnblogs.com/archimedes/p/mapreduce-principle.html,轉載請註明源地址。

Hadoop中的MapReduce

大規模數據處理時,MapReduce在三個層面上的基本構思

如何對付大數據處理:分而治之

  對相互間不具有計算依賴關係的大數據,實現並行最自然的辦法就是採取分而治之的策略

上升到抽象模型:Mapper與Reducer

  MPI等並行計算方法缺少高層並行編程模型,爲了克服這一缺陷,MapReduce借鑑了Lisp函數式語言中的思想,用Map和Reduce兩個函數提供了高層的並行編程抽象模型

上升到構架:統一構架,爲程序員隱藏系統層細節

  MPI等並行計算方法缺少統一的計算框架支持,程序員需要考慮數據存儲、劃分、分發、結果收集、錯誤恢復等諸多細節;爲此,MapReduce設計並提供了統一的計算框架,爲程序員隱藏了絕大多數系統層面的處理細節

1.對付大數據處理-分而治之

什麼樣的計算任務可進行並行化計算?

並行計算的第一個重要問題是如何劃分計算任務或者計算數據以便對劃分的子任務或數據塊同時進行計算。但一些計算問題恰恰無法進行這樣的劃分!

Nine women cannot have a baby in one month!

例如:Fibonacci函數:  Fk+2 = Fk + Fk+1 

前後數據項之間存在很強的依賴關係!只能串行計算! 

結論:不可分拆的計算任務或相互間有依賴關係的數據無法進行並行計算!

大數據的並行化計算

  一個大數據若可以分爲具有同樣計算過程的數據塊,並且這些數據塊之間不存在數據依賴關係,則提高處理速度的最好辦法就是並行計算

  例如:假設有一個巨大的2維數據需要處理(比如求每個元素的開立方),其中對每個元素的處理是相同的,並且數據元素間不存在數據依賴關係,可以考慮不同的劃分方法將其劃分爲子數組,由一組處理器並行處理

 

2.構建抽象模型-Map和Reduce

借鑑函數式設計語言Lisp的設計思想

—函數式程序設計(functional programming)語言Lisp是一種列表處理 語言(List processing),是一種應用於人工智能處理的符號式語言,由MIT的人工智能專家、圖靈獎獲得者John McCarthy於1958年設計發明。

—Lisp定義了可對列表元素進行整體處理的各種操作,如:

    如:(add #(1 2 3 4) #(4 3 2 1))   將產生結果: #(5 5 5 5)

—Lisp中也提供了類似於Map和Reduce的操作

    如: (map ‘vector #+ #(1 2 3 4 5)  #(10 11 12 13 14))

    通過定義加法map運算將2個向量相加產生結果#(11 13 15 17 19)

        (reduce #’+ #(11  13  15  17  19)) 通過加法歸併產生累加結果75

Map: 對一組數據元素進行某種重複式的處理

Reduce: 對Map的中間結果進行某種進一步的結果整

關鍵思想:爲大數據處理過程中的兩個主要處理操作提供一種抽象機制

MapReduce中的Map和Reduce操作的抽象描述

MapReduce借鑑了函數式程序設計語言Lisp中的思想,定義瞭如下的Map和Reduce兩個抽象的編程接口,由用戶去編程實現:

—map(k1; v1) → [(k2; v2)]

輸入:鍵值對(k1; v1)表示的數據

處理:文檔數據記錄(如文本文件中的行,或數據表格中的行)將以“鍵值對”形式傳入map函數;map函數將處理這些鍵值對,並以另一種鍵值對形式輸出處理的一組鍵值對中間結果   [(k2; v2)]

輸出:鍵值對[(k2; v2)]表示的一組中間數據

—reduce: (k2; [v2])  [(k3; v3)]

輸入: 由map輸出的一組鍵值對[(k2; v2)] 將被進行合併處理將同樣主鍵下的不同數值合併到一個列表[v2]中,故reduce的輸入爲(k2; [v2])

處理:對傳入的中間結果列表數據進行某種整理或進一步的處理,併產生最終的某種形式的結果輸出[(k3; v3)] 。

輸出:最終輸出結果[(k3; v3)]

Map和Reduce爲程序員提供了一個清晰的操作接口抽象描述

—各個map函數對所劃分的數據並行處理,從不同的輸入數據產生不同的中間結果輸出

—各個reduce也各自並行計算,各自負責處理不同的中間結果數據集合—進行reduce處理之前,必須等到所有的map函數做完,因此,在進入reduce前需要有一個同步障(barrier);這個階段也負責對map的中間結果數據進行收集整理(aggregation & shuffle)處理,以便reduce更有效地計算最終結果—最終彙總所有reduce的輸出結果即可獲得最終結果

基於MapReduce的處理過程示例--文檔詞頻統計:WordCount

設有4組原始文本數據:

Text 1: the weather is good         Text 2: today is good    

Text 3: good weather is good      Text 4: today has good weather

傳統的串行處理方式(Java):

String[] text = new String[] { “hello world”, “hello every one”, “say hello to everyone in the world” };
HashTable ht = new HashTable();    
for(i = 0; i < 3; ++i) {
    StringTokenizer st = new StringTokenizer(text[i]); 
    while (st.hasMoreTokens()) {  
        String word = st.nextToken();
        if(!ht.containsKey(word)) {  
            ht.put(word, new Integer(1));
        } else {
            int wc = ((Integer)ht.get(word)).intValue() +1;// 計數加1
            ht.put(word, new Integer(wc));
        }
    }
}
for (Iterator itr=ht.KeySet().iterator();  itr.hasNext(); ) {
    String word = (String)itr.next(); 
    System.out.print(word+ “: ”+ (Integer)ht.get(word)+“;   ”);
}

輸出:good:  5;   has: 1;  is: 3;   the: 1;   today: 2;    weather: 3

基於MapReduce的處理過程示例--文檔詞頻統計:WordCount

MapReduce處理方式

使用4個map節點:

map節點1:

  輸入:(text1, “the weather is good”)

  輸出:(the, 1), (weather, 1), (is, 1), (good, 1)

map節點2:

  輸入:(text2, “today is good”)

  輸出:(today, 1), (is, 1), (good, 1)

map節點3:

  輸入:(text3, “good weather is good”)

  輸出:(good, 1), (weather, 1), (is, 1), (good, 1)

map節點4:

  輸入:(text3, “today has good weather”)

  輸出:(today, 1), (has, 1), (good, 1), (weather, 1)

使用3個reduce節點:

MapReduce處理方式

MapReduce僞代碼(實現Map和Reduce兩個函數):

Class Mapper method map(String input_key, String input_value):
  // input_key: text document name 
  // input_value: document contents 
  for each word w in input_value: 
      EmitIntermediate(w, "1"); 

Class Reducer method reduce(String output_key, Iterator intermediate_values): 
  // output_key: a word 
  // output_values: a list of counts 
  int result = 0; 
  for each v in intermediate_values: 
      result += ParseInt(v);
  Emit(output_key, result);

3.上升到構架-自動並行化並隱藏低層細節

如何提供統一的計算框架

MapReduce提供一個統一的計算框架,可完成:

—計算任務的劃分和調度

—數據的分佈存儲和劃分

—處理數據與計算任務的同步

—結果數據的收集整理(sorting, combining, partitioning,…)

—系統通信、負載平衡、計算性能優化處理

—處理系統節點出錯檢測和失效恢復

MapReduce最大的亮點

—通過抽象模型和計算框架把需要做什麼(what need to do)與具體怎麼做(how to do)分開了,爲程序員提供一個抽象和高層的編程接口和框架

—程序員僅需要關心其應用層的具體計算問題,僅需編寫少量的處理應用本身計算問題的程序代碼

—如何具體完成這個並行計算任務所相關的諸多系統層細節被隱藏起來,交給計算框架去處理:從分佈代碼的執行,到大到數千小到單個節點集羣的自動調度使用

MapReduce提供的主要功能

—任務調度:提交的一個計算作業(job)將被劃分爲很多個計算任務(tasks), 任務調度功能主要負責爲這些劃分後的計算任務分配和調度計算節點(map節點或reducer節點); 同時負責監控這些節點的執行狀態, 並負責map節點執行的同步控制(barrier); 也負責進行一些計算性能優化處理, 如對最慢的計算任務採用多備份執行、選最快完成者作爲結果

—數據/代碼互定位:爲了減少數據通信,一個基本原則是本地化數據處理(locality),即一個計算節點儘可能處理其本地磁盤上所分佈存儲的數據,這實現了代碼向數據的遷移;當無法進行這種本地化數據處理時,再尋找其它可用節點並將數據從網絡上傳送給該節點(數據向代碼遷移),但將儘可能從數據所在的本地機架上尋找可用節點以減少通信延遲

—出錯處理:以低端商用服務器構成的大規模MapReduce計算集羣中,節點硬件(主機、磁盤、內存等)出錯和軟件有bug是常態,因此,MapReducer需要能檢測並隔離出錯節點,並調度分配新的節點接管出錯節點的計算任務
—分佈式數據存儲與文件管理:海量數據處理需要一個良好的分佈數據存儲和文件管理系統支撐,該文件系統能夠把海量數據分佈存儲在各個節點的本地磁盤上,但保持整個數據在邏輯上成爲一個完整的數據文件;爲了提供數據存儲容錯機制,該文件系統還要提供數據塊的多備份存儲管理能力
—Combiner和Partitioner:爲了減少數據通信開銷,中間結果數據進入reduce節點前需要進行合併(combine)處理,把具有同樣主鍵的數據合併到一起避免重複傳送; 一個reducer節點所處理的數據可能會來自多個map節點, 因此, map節點輸出的中間結果需使用一定的策略進行適當的劃分(partitioner)處理,保證相關數據發送到同一個reducer節點

基於Map和Reduce的並行計算模型

4.MapReduce的主要設計思想和特徵

1、向“外”橫向擴展,而非向“上”縱向擴展(Scale “out", not “up”)

     即MapReduce集羣的構築選用價格便宜、易於擴展的大量低端商用服務器,而非價格昂貴、不易擴展的高端服務器(SMP)—低端服務器市場與高容量Desktop PC有重疊的市場,因此,由於相互間價格的競爭、可互換的部件、和規模經濟效應,使得低端服務器保持較低的價格—基於TPC-C在2007年底的性能評估結果,一個低端服務器平臺與高端的共享存儲器結構的服務器平臺相比,其性價比大約要高4倍;如果把外存價格除外,低端服務器性價比大約提高12倍—對於大規模數據處理,由於有大量數據存儲需要,顯而易見,基於低端服務器的集羣遠比基於高端服務器的集羣優越,這就是爲什麼MapReduce並行計算集羣會基於低端服務器實現

2、失效被認爲是常態(Assume failures are common)  

MapReduce集羣中使用大量的低端服務器(Google目前在全球共使用百萬臺以上的服務器節點),因此,節點硬件失效和軟件出錯是常態,因而:—一個良好設計、具有容錯性的並行計算系統不能因爲節點失效而影響計算服務的質量,任何節點失效都不應當導致結果的不一致或不確定性;任何一個節點失效時,其它節點要能夠無縫接管失效節點的計算任務;當失效節點恢復後應能自動無縫加入集羣,而不需要管理員人工進行系統配置—MapReduce並行計算軟件框架使用了多種有效的機制,如節點自動重啓技術,使集羣和計算框架具有對付節點失效的健壯性,能有效處理失效節點的檢測和恢復。

3、把處理向數據遷移(Moving processing to the data)

—  傳統高性能計算系統通常有很多處理器節點與一些外存儲器節點相連,如用區域存儲網絡(SAN,Storage Area Network)連接的磁盤陣列,因此,大規模數據處理時外存文件數據I/O訪問會成爲一個制約系統性能的瓶頸。—爲了減少大規模數據並行計算系統中的數據通信開銷,代之以把數據傳送到處理節點(數據向處理器或代碼遷移),應當考慮將處理向數據靠攏和遷移。—MapReduce採用了數據/代碼互定位的技術方法,計算節點將首先將盡量負責計算其本地存儲的數據,以發揮數據本地化特點(locality),僅當節點無法處理本地數據時,再採用就近原則尋找其它可用計算節點,並把數據傳送到該可用計算節點。

4、順序處理數據、避免隨機訪問數據(Process data sequentially and avoid random access)

— 大規模數據處理的特點決定了大量的數據記錄不可能存放在內存、而只可能放在外存中進行處理。—磁盤的順序訪問和隨即訪問在性能上有巨大的差異

 例:100億(1010)個數據記錄(每記錄100B,共計1TB)的數據庫

   更新1%的記錄(一定是隨機訪問)需要1個月時間;而順序訪問並重寫所有數據記錄僅需1天時間!

 —MapReduce設計爲面向大數據集批處理的並行計算系統,所有計算都被組織成很長的流式操作,以便能利用分佈在集羣中大量節點上磁盤集合的高傳輸帶寬。

5、爲應用開發者隱藏系統層細節(Hide system-level details from the application developer)

—  軟件工程實踐指南中,專業程序員認爲之所以寫程序困難,是因爲程序員需要記住太多的編程細節(從變量名到複雜算法的邊界情況處理),這對大腦記憶是一個巨大的認知負擔,需要高度集中注意力—而並行程序編寫有更多困難,如需要考慮多線程中諸如同步等複雜繁瑣的細節,由於併發執行中的不可預測性,程序的調試查錯也十分困難;大規模數據處理時程序員需要考慮諸如數據分佈存儲管理、數據分發、數據通信和同步、計算結果收集等諸多細節問題—MapReduce提供了一種抽象機制將程序員與系統層細節隔離開來,程序員僅需描述需要計算什麼(what to compute), 而具體怎麼去做(how to compute)就交由系統的執行框架處理,這樣程序員可從系統層細節中解放出來,而致力於其應用本身計算問題的算法設計

6、平滑無縫的可擴展性(Seamless scalability)

  主要包括兩層意義上的擴展性:數據擴展和系統規模擴展。—理想的軟件算法應當能隨着數據規模的擴大而表現出持續的有效性,性能上的下降程度應與數據規模擴大的倍數相當—在集羣規模上,要求算法的計算性能應能隨着節點數的增加保持接近線性程度的增長—絕大多數現有的單機算法都達不到以上理想的要求;把中間結果數據維護在內存中的單機算法在大規模數據處理時很快失效;從單機到基於大規模集羣的並行計算從根本上需要完全不同的算法設計—奇妙的是,MapReduce幾乎能實現以上理想的擴展性特徵。  多項研究發現基於MapReduce的計算性能可隨節點數目增長保持近似於線性的增長

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