我們為什么要關注MapReduce?
1.什么是MapReduce?
MapReduce 是由Google公司的Jeffrey Dean 和 Sanjay Ghemawat 開發的一個針對大規模群組中的海量數據處理的分布式編程模型。MapReduce實現了兩個功能。Map把一個函數應用于集合中的所有成員,然后返回一個基于這個處理的結果集。而Reduce是把從兩個或更多個Map中,通過多個線程,進程或者獨立系統并行執行處理的結果集進行分類和歸納。Map() 和 Reduce() 兩個函數可能會并行運行,即使不是在同一的系統的同一時刻。
Google 用MapReduce來索引每個抓取過來的Web頁面。它取代了2004開始試探的最初索引算法,它已經證明在處理大量和非結構化數據集時更有效。用不同程序設計語言實現了多個MapReduce,包括 Java, C++, Python, Perl, Ruby和C, 其它語言。在某些范例里,如Lisp或者Python, Map() 和Reduce()已經集成到語言自身的結構里面。通常,這些函數可能會如下定義:
List2 map(Functor1, List1);
Object reduce(Functor2, List2);
Map()函數把大數據集進行分解操作到兩個或更多的小“桶”。而一個“桶”則是包含松散定義的邏輯記錄或者文本行的集合。每個線程,處理器或者系統在獨立的“桶”上執行Map()函數,去計算基于每個邏輯記錄處理的一系列中間值。合并的結果值就會如同是單個Map()函數在單個“桶”上完全一致。Map()函數的通常形式是:
map(function, list) {
foreach element in list {
v = function(element)
intermediateResult.add(v)
}
} // map
Reduce()函數把從內存,磁盤或者網絡介質提取過來的一個或多個中間結果列表,對列表中的每個元素逐一執行一個函數。完成操作的最終結果是通過對所有運行reduce()操作的處理結果進行分類和解釋。Reduce()函數的通常形式是:
reduce(function, list, init) {
result = init
foreach value in list {
result = function(result, value)
}
outputResult.add(result)
}
MapReduce的實現把業務邏輯從多個處理邏輯中分離出來了,map()和reduce()函數跨越多個系統,通過共享池和部分RPC的形式來達到彼此之間的同步和通信。這里的業務邏輯是由用戶自定義的函數子實現,并且這些函數子只能用在邏輯記錄處理的工作上,而不用關心多個處理操作的問題。這樣一旦MapReduce框架就位,就能通過大量的處理器快速的轉變為應用系統的并行處理。因為開發人員可以把精力花在寫函數子上面了。MapReduce簇可以通過替換函數子和提供新的數據源來重新使用,而無需每次都對整個應用進行編譯,測試和部署。
2.實現MapReduce
MapReduce()的目的是為了大型集群的系統能在大數據集上進行并行工作。
圖1顯示了一個運行在一個主系統上的主程序,協調其它實例進行map()或者reduce()操作,然后從每個reduce操作中收集結果。

【圖 1】
主應用程序負責把基礎的數據集分解到“桶”中。桶的最佳大小依賴于應用,結點的數量和可用的I/O帶寬。這些“桶”通常存儲在磁盤,但有必要也可能分散到主存中,這依賴于具體的應用。“桶”將作為map()函數的輸入。
主應用程序也負責調度和分散幾個MapReduce的核心備份,除了控制者給空閑的處理器或線程分配了調整map()和reduce()任務之外,它們是完全相致的。控制者會持續跟蹤每個map()和reduce()任務的狀態,并且可以作為map()和reduce()任務之間路由中間結果的管道。每個map() 任務處理器完全指派給“桶”,然后產生一個存到共享存儲區域的中間結果集。共享存儲可以設計成分布緩存,磁盤或其它設備等形式。當一個新的中間結果寫入共享存儲區域后,任務就向控制者發出通知,并提供指向其共享存儲位置的句柄。
當新的中間結果可用時,控制者分配reduce()任務。這個任務通過應用獨立的中間鍵值來實現排序,使相同的數據能聚集在一起,以提供更快的檢索。大塊的結果集可以進行外部排序,reduce()任務遍歷整個排序的數據,把每個唯一的鍵和分類的結果傳遞到用戶的reduce() 函數子進行處理。
通過map()和reduce()實例終端的處理,當所有的“桶”都用完,然后全部的reduce()任務就通知控制者,以說明它們的結果已經產生了。控制者就向主應用程序發出檢索這個結果的信號。主應用程序可能就直接操作這些結果,或者重新分配到不同的MapReduce控制者和任務進行進一步的處理,
顯示情況下MapReduce的實現可能通常分配給控制者,map()和reduce()任務分配給單獨的系統。Google操作模型是基于跨越大量的廉價硬件設備上組成的集群或者白盒子上面部署MapReduce應用。為了處理它自己的桶的需要,每個白盒子都有本地存儲裝置,一個合理數量的私有內存(2到4GB RAM)和至少兩個處理內核。白盒子是可互相交換的,主應用程序可能把集群中的任何機器指派為控制者,而這個機器就把map()和reduce()任務分派給其它連接的白盒子。
3.基于Java的MapReduce 實現
Google的環境是為它自己的需求定制和適應它們的操作環境。比如,為了它的MapReduce實現更好的執行這種類型的操作,使其更優化,Google使用了專有的文件系統用來存儲文件。相反,企業應用系統都是建立在Java或類似的技術上面的,它們依賴于已有的文件系統,通信協議和應用棧。
一個基于Java的MapReduce實現應該考慮到已存在的數據存儲設備,將來部署到的結構里面支持那種協議,有哪些內部API和支持部署那種第三方產品(開源的或商業的)。圖2顯示了通常的架構是如何通過映射到已有的、健壯的Java開源架構來實現的。

【圖 2】
這個架構采用了已有的工具,比如Terracotta和Mule,它們經常出現在很多企業系統的組織里面。已物理或虛擬系統形成存在的白盒子通過有效簡單的配置和部署,設計成MapReduce群組中的一部分。為了效率,一個很大的系統可以分解到幾個虛擬機器上,如果需要可以分配更多的結點。可以根據容量的問題和處理器的有效利用賴決定是否在群集中使用物理“白盒子”,虛擬機或者它們兩者的結合。
Terracotta 集群技術是map()和reduce()任務之間共享數據的很好選擇,因為它把map()和reduce()之間的通信過程,包括共享文件或者使用RPC調用已初始處理結構都做了抽象。
從前面章節的描述知道,Map()和reduce()任務是在同一個核心應用中實現的。用來共享中間結構集的數據結構可以保持在內存的數據結構中,通過Terracotta透明的共享交換。
由跨域集群的MapReduce產生的進程內通信問題,自從Terracotta運行時掌管著這些共享數據結構后就不存在了。不同于實現一個復雜的信號系統,所有的map()任務需要標記內存中的中間結構集,然后reduce()任務就直接提取它們。
控制者和主應用程序都會在同時處在等待狀態一段時間,即使是MapReduce集群有大量可用的并行處理能力。這兩個組件之間以及當歸并完成后的reduce()任務和控制者之間,都是通過Mule的ESB傳遞信號的。通過這種方式,為了其它應用的處理,輸出結構可以排到隊列,或者像前面章節講的一樣,為了其他MapReduced的處理,一個Mule服務對象(or UMO)可以把這些輸出結果分解到“桶”中。
通過主流的企業應用協議或者完全的原始TCP/IP Sockets,Mule支持在內存中進行同步和異步的數據傳輸. Mule可以用于在同一臺機器執行的應用系統,跨域不同的數據中心或者在完全不同地方且被程序員分開標識的本地終端結點互相傳遞輸出結構集。其它基于Java的實現可以通過Hadoop, 是一個用于運行應用程序在大型集群的廉價硬件設備上的框架, 它是基于lucene框架。Hadoop是一個開源,點對點,通用的MapReduce實現。
4.結論
不管使用什么技術,索引大量非結構化數據是一件很艱難的任務。應用傳統的算法和啟發式方法很難維護,因為隨著時間的推移,系統的性能下降使系統變得難以控制。RDBMS 能有效的用于索引和檢索大量的結構化數據集合,但不適合用于非結構化的數據。MapReduce為并行系統的數據處理,提供了一個簡單,優雅的解決方案,優勢有:
l 歸并成本
l 程序員的高產出,因為用并行的代碼獨立實現了業務邏輯
l 比傳統RDBMS技術更好的性能和更優的結果。
l 使用Java企業框架和開發人員都熟悉的已有的技術和工具更易部署
用MapReduce, Google有令人印象深刻的跟蹤記錄,而且每天出現的工具都能輕易的融入到這個體系中。在企業級的應用系統中,如果你準備開始一個快速,簡單的任務,例如根據IP地址分析請求的擁堵模型到你的web集群中,或者類似的東西。一個這樣的練習將會很大程度上提高你對關鍵系統面臨的問題和挑戰的認識,MapReduce則就是為這些而準備的。
英文原址:http://www.theserverside.com/tt/knowledgecenter-tc/knowledgecenter-tc.tss?l=MapReduce