這是一個由simviso團隊所組織進行的基於mit分佈式系統課程翻譯的系列,由知秋帶領和其餘成員一塊兒翻譯的課程以及課程當中涉及的論文翻譯。
本文章參與人員程序員
參與人員 | 參與範圍 |
---|---|
知秋 | 審校 |
虛生花 | 翻譯 |
概要編程
MapReduce是一種編程模型,它是一種用於處理和生成大型數據集的實現。用戶經過指定一個用來處理鍵值對(Key/Value)的map函數來生成一箇中間鍵值對集合。而後,再指定一個reduce函數, 它用來合併全部的具備相同中間key的中間value 。現實生活中有許多任務能夠經過該模型進行表達,具體案例會在論文中展示出來。數組
以這種函數式風格編寫的程序可以在一個大型商用機器集羣上自動並行執行。這個系統在運行時只關心:如何分割輸入數據,在大量計算機所組成的集羣上的調度問題,集羣中計算機的故障處理,管理集羣中計算機之間的必要通訊。使用MapReduce編程模型可讓那些沒有並行計算和分佈式系統開發經驗的程序員有效的使用分佈式系統的資源。網絡
咱們實現的MapReduce能夠在一個大型的商用計算機集羣上運行,而且具有高度擴展性:一個標準的MapReduce計算能夠在數千臺機器上處理TB級的數據。程序員會以爲該系統易於使用。目前在谷歌已經實現了數以百計的MapReduce程序,在谷歌的集羣上,天天都有1000多個MapReduce的工做在執行。負載均衡
在過去五年裏,做者以及許多其餘在谷歌工做的人已經實現了數百種用於特殊目的的計算。它們能夠用來處理大量原始數據,例如:爬取的文檔,網頁請求日誌等等。並以此來計算出各類衍生數據,例如:倒排索引,Web文檔的各類圖表示,每臺主機所抓取頁面數的摘要,以及特定某天中最頻繁的查詢集等等。大部分這種計算從概念上來說都很簡單。可是,輸入的數據量一般很是巨大,而且爲了能在一個合理的時間內完成,計算任務也不得不分配給成百上千臺機器去執行。如何並行化計算,分配數據以及處理故障的問題,全部的問題都糾纏在一塊兒,這就須要大量的代碼來對它們進行處理。所以,這也使得本來簡單的計算變得極爲複雜,並且難以處理。分佈式
爲了應對這種複雜性,咱們設計了一種新的抽象,它可讓咱們表達咱們所試圖執行的簡單計算,但該庫中隱藏了並行化,容錯,數據分發以及負載均衡這些混亂的細節。咱們這種抽象的設計靈感來源於Lisp和許多其餘函數式語言中存在的map和reduce原語。咱們意識到,大多數計算都涉及到對輸入中的每一個邏輯記錄進行_map_操做,以便於計算出一箇中間鍵值對的集合。而後,爲了恰當的整合衍生數據,咱們對共用相同鍵的全部值進行_reduce_操做。經過使用具有用戶所指定的_map_和_reduce_操做的函數式模型,這使得咱們可以輕鬆並行化大型計算,而且使用從新執行的結果做爲容錯的主要機制。函數
這項工做的主要貢獻在於提供了一個簡單而強大的接口,該接口可實現大規模計算的自動並行化和分佈式執行。經過使用該接口的實現,從而在大型商用計算機集羣上得到了高性能。性能
本文的第2章節描述了該基礎編程模型並給出了一些案例。第3章節則是關於咱們針對集羣的計算環境所量身定製的MapReduce接口的實現。第4章節介紹了咱們所找到的對於該編程模型的一些有用改進。第5章節則是關於咱們經過一系列任務對咱們所實現的MapReduce進行的性能測試。第6章節則探索了MapReduce在谷歌中的一些應用,這其中包括了咱們使用它來重寫咱們的索引系統的一些經驗。第7章節討論了一些相關以及往後要作的工做。測試
該計算任務將一個鍵值對集合做爲輸入,並生成一個鍵值對集合做爲輸出。MapReduce這個庫的用戶將這種計算任務以兩個函數進行表達,即Map和Reduce。spa
由用戶所編寫的Map函數接收輸入,並生成一箇中間鍵值對集合。MapReduce這個庫會將全部共用一個鍵的值組合在一塊兒,並將它們傳遞給Reduce函數。
Reduce函數也是由用戶所編寫。它接受一箇中間鍵以及該鍵的值的集合做爲輸入。它會將這些值合併在一塊兒,以此來生成一組更小的值的集合。一般每次調用Reduce函數所產生的值的結果只有0個或者1個。中間值經過一個迭代器來傳遞給用戶所編寫的Reduce函數。這使得咱們能夠處理這些由於數據量太大而沒法存放在內存中的存儲值的list列表了。
咱們能夠思考下這樣一個場景,咱們要從大量的文檔中計算出每一個單詞的出現次數。用戶將會編寫出相似於下方僞代碼的代碼:
map(Stringkey,Stringvalue): // key: document name // value: document contents for each word w in value: EmitIntermediate(w,"1"); reduce(String key,Iterator values): // key: a word // values: a list of counts int result =0; for each v in values: result += ParseInt(v); Emit(AsString(result));
map
函數會返回一個單詞加上它出現的次數的鍵值對(在這個例子中,返回的出現次數就是1)。reduce
函數會將該單詞的出現次數統計在一塊兒。
此外,用戶經過編寫代碼,傳入輸入和輸出文件的名字,以及可選的調節參數來建立一個符合MapReduce模型規範的對象。接着,用戶調用MapReduce函數,並將這個對象傳入該函數。用戶的代碼和MapReduce庫(該庫是由C++實現的)連接在一塊兒,附錄A中會提供該案例的完整代碼。
儘管在前面的僞代碼中的輸入和輸出的類型都是String,可是從概念上來講,用戶所提供的map
和reduce
函數都有相關聯的類型。
map(k1,v1) -->list(k2,v2) reduce(k2,list(v2)) -->list(v2)
例如,輸入的鍵和值與輸出的鍵和值來自於不一樣的地方。此外,中間的鍵和值與輸出的鍵和值在類型上相同。
在咱們的C++實現中,咱們使用String類型做爲用戶所定義的函數的輸入和輸出的類型,用戶在本身的代碼中對字符串進行適當的類型轉換。
此處有一些能夠很容易使用MapReduce模型來表示的簡單例子:
分佈式過濾器:Map
函數會發出(emit)匹配某個規則的一行。Reduce
函數是一個恆等函數,即把中間數據複製到輸出。(虛生花注:恆等函數是數學中是一種沒有任何做用的函數,它的輸入等於輸出,即f(x)=x)。
計算URL的訪問頻率:map
函數用來處理網頁請求的日誌,並輸出(URL,1)。reduce
函數則用於將相同URL的值所有加起來,並輸出(URL, 訪問總次數)
這樣的鍵值對結果。
倒轉網絡連接圖:map
函數會在源頁面中找到全部的目標URL,並輸出<target, source>這樣的鍵值對。reduce
函數會將給定的目標URL的全部連接組合成一個列表,輸出<target, list(source)>這樣的鍵值對。
每臺主機上的檢索詞頻率:term(這裏是指搜索系統裏的某一項東西,這裏指檢索詞)vector(這裏指數組)將一個文檔或者是一組文檔中出現的最重要的單詞歸納爲_<單詞,頻率>_ 這樣的鍵值對列表,對於每一個輸入文檔,map函數會輸出這樣一對鍵值對<hostname, term vector>(其中hostname是從文檔中的URL裏提取出來的)。Reduce函數接收給定主機的全部每個文檔的term vector。它會將這些term vector加在一塊兒,並去除頻率較低的term,而後輸出一個最終鍵值對<hostname, term vector>。
倒排索引:map
函數會對每一個文檔進行解析,並輸出<word, 文檔ID>這樣的鍵值對序列。reduce
函數所接受的輸入是一個給定詞的全部鍵值對,接着它會對全部文檔ID進行排序,而後輸出<word, list(文檔ID)>。全部輸出鍵值對的集合能夠造成一個簡單的倒排索引。咱們能簡單的計算出每一個單詞在文檔中的位置。
分佈式排序:map
函數會從每條記錄中提取出一個key,而後輸出<key, record>這樣的鍵值對。reduce
函數對這些鍵值對不作任何修改,直接輸出。這種計算任務依賴分區機制(詳見章節4.1)以及排序屬性(詳見章節4.2)。