天天看點

《MapReduce設計模式》一1.3 MapReduce和Hadoop簡介

本節書摘來異步社群《mapreduce設計模式》一書中的第1章,第1.3節,作者: 【美】donald miner , adam shook 譯者: 徐钊 , 趙重慶 責編: 楊海玲,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

1.3 mapreduce和hadoop簡介

本節主要向讀者簡單介紹hadoop中的mapreduce架構,因為本書的示例代碼都是基于hadoop的。想要更加深入地了解hadoop的讀者可以參考tom white的《hadoop:the definitive guide》一書以及apache hadoop的官方網站。這些資料将幫助你簡單地部署一個開發環境或生産環境來驗證本書的示例代碼。

hadoop mapreduce作業被分成一系列運作在分布式叢集中的map任務和reduce任務。每個任務都工作在被指定的小的資料子集上,是以負載是遍布叢集中各個節點上的。map任務主要負責資料的載入、解析、轉換和過濾。每個reduce任務負責處理map任務輸出結果的一個子集。然後,reducer任務從mapper任務處複制map任務的中間資料,進行分組和聚合操作。從簡單的數值聚合到複雜的關聯操作以及笛卡兒積操作,mapreduce通過如此簡潔的架構來解決範圍廣泛的諸多問題,這确實讓人難以置信。

mapreduce作業的輸入是一系列存儲在hadoop分布式檔案系統(hadoop distributed file system,hdfs)上的檔案。在hadoop中,這些檔案通過輸入格式(input format)被分成了一系列的輸入split(input split)。輸入split可以看作是檔案在位元組層面的分塊表示,每個split由一個map任務負責處理。

hadoop中的每個map任務可以細分成4個階段:record reader、mapper、combiner和partitioner。map任務的輸出被稱為中間鍵和中間值,會被發送到reducer做後續處理。reduce任務可以分為4個階段:混排(shuffle)、排序(sort)、reducer和輸出格式(output format)。map任務運作的節點會優先選擇在資料所在的節點,是以,一般可以通過在本地機器上進行計算來減少資料的網絡傳輸。

record reader

record reader通過輸入格式将輸入split解析成記錄。record reader的目的是将輸入資料解析成記錄,但不負責解析記錄本身。它将資料轉換為鍵/值(key/value)對的形式,并傳遞給mapper處理。通常鍵是資料在檔案中的位置,值是組成記錄的資料塊。定制record reader已經超出了本書的讨論範圍,是以我們假設讀者已經有合适的record reader來解析需要處理的資料。

map

在mapper中,使用者定義的map代碼通過處理record reader解析的每個鍵/值對來産生0個或多個新的鍵/值對結果。鍵/值的選擇對mapreduce作業的完成效率來說非常重要。鍵是資料在reducer中處理時被分組的依據,值是reducer需要分析的資料。如何選擇鍵/值對的更多細節會在本書後面的設計模式中進行詳細解釋。兩個不同的mapreduce設計模式之間的一個重要差別就在于鍵/值對的語義。

combiner

combiner是一個可選的本地reducer,可以在map階段聚合資料。combiner通過執行使用者指定的來自mapper的中間鍵對map的中間結果做單個map範圍内的聚合。例如,一個聚合的計數是每個部分計數的總和,使用者可以先将每個中間結果取和,再将中間結果的和相加,進而得到最終結果。在很多情況下,這樣可以明顯地減少通過網絡傳輸的資料量。在網絡上發送一次(hello world,3)要比三次(hello world,1)節省更多的位元組量。因為combiner的應用廣泛,是以我們将在後續的模式中對其進行更深入的講解。很多新hadoop代碼開發者可能會忽視combiner,但通常combiner可以産生特别大的性能提升,并且沒有副作用。我們将在後續的章節中指出哪些模式可以通過使用combiner得到優化,以及哪些模式是不能使用combiner的。combiner不能保證執行,是以不能作為整個算法的一部分。

partitioner

partitioner的作用是将mapper(如果使用了combiner的話就是combiner)輸出的鍵/值對拆分為分片(shard),每個reducer對應一個分片。預設情況下,partitioner先計算目标的散列值(通常為md5值)。然後,通過reducer個數執行取模運算key.hashcode()%(reducer的個數)。這種方式不僅能夠随機地将整個鍵空間平均分發給每個reducer,同時也能確定不同mapper産生的相同鍵能被分發至同一個reducer。使用者可以定制partitioner的預設行為,并可以使用更進階的模式,如排序。當然,一般情況下是不需要改寫partitioner的。對于每個map任務,其分好區的資料最終會寫入本地檔案系統,等待其各自的reducer拉取。

混排和排序

reduce任務開始于混排和排序這一步驟。該步驟主要是将所有partitioner寫入的輸出檔案拉取到運作reducer的本地機器上,然後将這些資料按照鍵排序并寫到一個較大的資料清單中。排序的目的是将相同鍵的記錄聚合在一起,這樣其所對應的值就可以很友善地在reduce任務中進行疊代處理。這個過程完全不可定制,而且是由架構自動處理的。開發人員隻能通過自定義comparator對象來确定鍵如何排序和分組。

reduce

reducer将已經分好組的資料作為輸入,并依次為每個鍵對應分組執行reduce函數。reduce函數的輸入是鍵以及包含與該鍵對應的所有值的疊代器。在後文介紹的模式中,我們将看到在這個函數中有很多種處理方法。這些資料可以被聚合、過濾或以多種方式合并。當reduce函數執行完畢後,會将0個或多個鍵/值對發送到最後的處理步驟——輸出格式。和map函數一樣,因為reduce函數是業務處理邏輯的核心部分,是以不同作業的reduce函數也不相同。

輸出格式

輸出格式擷取reduce函數輸出的最終鍵/值對,并通過record writer将它寫入到輸出檔案中。每條記錄的鍵和值預設通過tab分隔,不同記錄通過換行符分隔。雖然一般情況下可以通過自定義實作非常多的輸出格式,但是,不管是什麼格式,最終的結果都将寫到hdfs上。和record reader一樣,如何定制輸出格式不在本書的讨論範圍,因為那是對i/o的簡單處理。