分佈式計算模式之MapReduce

前言

前面文章中介紹兩層調度時提到,Mesos 的第二層調度是由 Framework 完成的。這裏的 Framework 通常就是計算框架,比如 Hadoop、Spark 等。用戶基於這些計算框架,可以完成不同類型和規模的計算。
那麼,在接下來就來介紹分佈式計算技術”了。分佈式領域的4 種計算模式:MapReduceStreamActor流水線

計算問題處理思想之分而治之

分而治之的基本思想是將一個複雜的、難以直接解決的大問題,分割成一些規模較小的、可以比較簡單的或直接求解的子問題,這些子問題之間相互獨立且與原問題形式相同,遞歸地求解這些子問題,然後將子問題的解合併得到原問題的解。
那麼,在分佈式領域,具體有哪些問題適合採用分治法呢?要回答這個問題,我們先看下適合分治法的問題具有哪些特徵吧。

  • 問題規模比較大或複雜,且問題可以分解爲幾個規模較小的、簡單的同類型問題進行求解;
  • 子問題之間相互獨立,不包含公共子問題;
  • 子問題的解可以合併得到原問題的解。

這種分治的思想廣泛應用於計算機科學的各個領域中,分佈式領域中的很多場景和問題也非常適合採用這種思想解決,併爲此設計出了很多計算框架。比如,Hadoop 中的 MapReduce。
同時,根據這些特徵,我們可以推導出,採用分治法解決問題的核心步驟是:

  • 分解原問題:將原問題分解爲若干個規模較小,相互獨立,且與原問題形式相同的子問題;
  • 求解子問題:若子問題規模較小且容易被解決則直接求解,否則遞歸地求解各個子問題;
  • 合併解:就是將各個子問題的解合併爲原問題的解;

分治法原理

Google 提出的 MapReduce 分佈式計算模型(Hadoop MapReduce 是 Google 的開源實現),作爲分治法的典型代表,最開始用於搜索領域,後來被廣泛用於解決各種海量數據的計算問題。

抽象模型

如下圖所示,MapReduce 分爲 MapReduce 兩個核心階段:

  • Map 對應“分”,即把複雜的任務分解爲若干個“簡單的任務”執行;
  • Reduce 對應着“合”,即對 Map 階段的結果進行彙總。

在這裏插入圖片描述
在第一階段,也就是 Map 階段,將大數據計算任務拆分爲多個子任務,拆分後的子任務通常具有如下特徵:

  • 相對於原始任務來說,劃分後的子任務與原任務是同質的,比如原任務是統計全國人口數,拆分爲統計省的人口數子任務時,都是統計人口數;
  • 並且,子任務的數據規模和計算規模會小很多。
  • 多個子任務之間沒有依賴,可以獨立運行、並行計算,比如按照省統計人口數,統計河北省的人口數和統計湖南省的人口數之間沒有依賴關係,可以獨立、並行的統計。

第二階段,也就是 Reduce 階段,第一階段拆分的子任務計算完成後,彙總所有子任務的計算結果,以得到最終結果。也就是,彙總各個省統計的人口數,得到全國的總人口數。

MapReduce 工作原理

在這裏插入圖片描述
如上圖所示,MapReduce 主要包括以下三種組件:

  • Master,也就是 MRAppMaster,該模塊像一個大總管一樣,獨掌大權,負責分配任務,協調任務的運行,併爲 Mapper 分配 map() 函數操作、爲 Reducer 分配 reduce() 函數操作。
  • Mapper worker,負責 Map 函數功能,即負責執行子任務。
  • Reducer worker,負責 Reduce 函數功能,即負責彙總各個子任務的結果。
    基於這三種組件,MapReduce 的工作流程如下所示:
    在這裏插入圖片描述
    程序從 User Program 開始進入 MapReduce 操作流程。其中圖中的“step1,step2,…,step6”表示操作步驟。
  • step1:User Program 將任務下發到 MRAppMaster 中。然後,MRAppMaster 執行任務拆分步驟,把User Program 下發的任務劃分成 M 個子任務(M 是用戶自定義的數值)。假設,MapReduce 函數將任務劃分成了 5個,其中 Map 作業有 3 個,Reduce 作業有 2 個;集羣內的MRAppMaster 以及 Worker節點都有任務的副本。
  • step2:MRAppMaster 分別爲 Mapper 和 Reducer 分配相應的 Map 和 Reduce作業。Map 作業的數量就是劃分後的子任務數量,也就是 3 個;Reduce 作業是 2 個。
  • step3:被分配了 Map 作業的 Worker,開始讀取子任務的輸入數據,並從輸入數據中抽取出 <key, value> 鍵值對,每一個鍵值對都作爲參數傳遞給 map()函數。
  • step4:map() 函數的輸出結果存儲在環形緩衝區 kvBuffer 中,這些 Map 結果會被定期寫入本地磁盤中,被存儲在 R個不同的磁盤區。這裏的 R 表示 Reduce 作業的數量,也是由用戶定義的。在這個案例中,R=2。此外,每個 Map結果的存儲位置都會上報給 MRAppMaster。
  • step5:MRAppMaster 通知 Reducer它負責的作業在哪一個分區,Reducer 遠程讀取相應的 Map 結果,即中間鍵值對。當 Reducer把它負責的所有中間鍵值對都讀過來後,首先根據鍵值對的 key 值對中間鍵值對進行排序,將相同 key 值的鍵值對聚集在一起,從而有利於Reducer 對 Map 結果進行統計。
  • step6:Reducer 遍歷排序後的中間鍵值對,將具有相同 key值的鍵值對合並,並將統計結果作爲輸出文件存入負責的分區中。

從上述流程可以看出,整個 MapReduce 的工作流程主要可以概括爲 5 個階段,即:Input(輸入)Splitting(拆分)Mapping(映射)、**Reducing(化簡)**以及 Final Result(輸出)。所有 MapReduce 操作執行完畢後,MRAppMaster 將 R 個分區的輸出文件結果返回給 User Program,用戶可以根據實際需要進行操作。比如,通常並不需要合併這 R 個輸出文件,而是將其作爲輸入交給另一個 MapReduce 程序處理。

MapReduce 實踐應用

接下來通過一個電商統計用戶消費記錄的例子,進一步加深一下對MapReduce 功能的理解。
每隔一段時間,電商都會統計該時期平臺的訂單記錄,從而分析用戶的消費傾向。在不考慮國外消費記錄的前提下,全國範圍內的訂單記錄已經是一個很大規模的工程了。在前面的文章中我也提到過,電商往往會在每個省份、多個城市分佈式地部署多個服務器,用於管理某一地區的平臺數據。因此,針對全國範圍內的消費統計,可以拆分成對多個省份的消費統計,並再一次細化到統計每一個城市的消費記錄。
爲方便描述,假設我們現在要統計蘇錫常地區第二季度手機訂單數量 Top3 的品牌。我們來看看具體的統計步驟吧。

  1. 任務拆分(Splitting 階段)。根據地理位置,分別統計蘇州、無錫、常州第二季度手機訂單 Top3 品牌,從而將大規模任務劃分爲 3 個子任務。
  2. 通過循環調用 map() 函數,統計每個品牌手機的訂單數量。其中,key 爲手機品牌,value 爲手機購買數量(單位:萬臺)。如下圖 Mapping 階段所示(爲簡化描述,圖中直接列出了統計結果)。
  3. 與前面講到的計算流程不同的是,Mapping 階段和 Reducing 階段中間多了一步 Shuffling 操作。Shuffling 階段主要是讀取 Mapping 階段的結果,並將不同的結果劃分到不同的區。在大多數參考文檔中,Mapping 和 Reducing 階段的任務分別定義爲映射以及歸約。但是,在映射之後,要對映射後的結果進行排序整合,然後才能執行歸約操作,因此往往將這一排序整合的操作單獨放出來,稱之爲 Shuffling 階段。
  4. Reducing 階段,歸併同一個品牌的購買次數。得到蘇錫常地區第二季度 Top3 品牌手機的購買記錄。

在這裏插入圖片描述
由上述流程可以看出,Map/Reduce 作業和 map()/reduce() 函數是有區別的:

  • Map 階段由一定數量的 Map 作業組成,這些 Map 作業是併發任務,可以同時運行,且操作重複。Map 階段的功能主要由 map() 函數實現。每個 Map 作業處理一個子任務(比如一個城市的手機消費統計),需要調用多次 map() 函數來處理(因爲城市內不同的居民傾向於不同的手機)。
  • Reduce 階段執行的是彙總任務結果,遍歷 Map 階段的結果從而返回一個綜合結果。與 Reduce 階段相關的是 reduce() 函數,它的輸入是一個鍵(key)和與之對應的一組數據(values),其功能是將具有相同 key 值的數據進行合併。Reduce 作業處理一個分區的中間鍵值對,期間要對每個不同的 key 值調用一次 reduce() 函數。在完成 Map 作業後,每個分區中會存在多個臨時文件;而執行完 Reduce 操作後,一個分區最終只有一個輸出文件。

在這裏插入圖片描述

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