課程b站視頻地址: MIT 6.824 Distributed Systems Spring 2020 分布式系統(tǒng)
推薦伴讀讀物:
- 極客時(shí)間 – 大數(shù)據(jù)經(jīng)典論文解讀
- DDIA – 數(shù)據(jù)密集型應(yīng)用
- 大數(shù)據(jù)相關(guān)論文中譯版本
本節(jié)預(yù)習(xí)作業(yè):
- MapReduce 論文(原版 - 英譯)
- MapReduce 論文(中譯)
引言
為什么我們需要使用分布式系統(tǒng):
- 為了更高的計(jì)算性能 , 大量的并行運(yùn)算,大量的CPU,內(nèi)存和磁盤都在并行運(yùn)行
- 更好的容錯(cuò)率(tolerate faults) , 同時(shí)有多臺(tái)計(jì)算機(jī)執(zhí)行一個(gè)任務(wù),就算其中一臺(tái)掛掉了,任務(wù)也可以切換到另一臺(tái)繼續(xù)執(zhí)行
- 一些問題天然在空間上是分布的,如銀行間的轉(zhuǎn)賬操作
- 出于安全考慮進(jìn)行隔離,當(dāng)需要和一些不被信任的代碼進(jìn)行交互時(shí),可以將代碼分散在多處運(yùn)行,通過特定的網(wǎng)絡(luò)協(xié)議進(jìn)行通信,這樣可以限制出錯(cuò)域
分布式系統(tǒng)不是銀彈,它會(huì)使簡(jiǎn)單的系統(tǒng)變得復(fù)雜,“如無(wú)必要,勿增實(shí)體” 。
本課程的重點(diǎn)討論在: 性能和容錯(cuò),下面我們來(lái)看看實(shí)現(xiàn)分布式系統(tǒng)的挑戰(zhàn)在哪里呢?
- 多服務(wù)并發(fā)執(zhí)行帶來(lái)的并發(fā)問題和時(shí)間依賴問題(同步,異步)
- 局部故障的難以預(yù)料,如網(wǎng)絡(luò)中斷或不穩(wěn)定
- 如果合理設(shè)計(jì)讓分布式系統(tǒng)達(dá)到我們期望的性能
抽象和實(shí)現(xiàn)
分布式系統(tǒng)由三大基礎(chǔ)架構(gòu)組成:
- 存儲(chǔ)
- 通信(網(wǎng)絡(luò))
- 計(jì)算
其中,存儲(chǔ)是我們最為關(guān)注的,因?yàn)槠涠x明確且直觀,我們曉得如何構(gòu)建和使用存儲(chǔ)系統(tǒng),也曉得如何利用它來(lái)構(gòu)建多副本,高容錯(cuò),高性能的分布式系統(tǒng)。
關(guān)于通信,這里更多只是作為建立分布式系統(tǒng)的工具之一,大部分情況下都是指通過網(wǎng)絡(luò)進(jìn)行通信,關(guān)于如何確保網(wǎng)絡(luò)通信的可靠性,可以學(xué)習(xí)MIT 6.829這門課程。
對(duì)于存儲(chǔ)和計(jì)算,我們期望能夠?qū)ν馓峁┮恍┏橄筮^的簡(jiǎn)單接口,讓第三方應(yīng)用能夠快速接入使用,并且借助這些抽象的接口,將分布式特性隱藏在整個(gè)系統(tǒng)內(nèi)。站在應(yīng)用程序的角度來(lái)看,整個(gè)系統(tǒng)是一個(gè)非分布式的系統(tǒng),就像一個(gè)文件系統(tǒng)或者一個(gè)普通的單體系統(tǒng),對(duì)外提供一個(gè)簡(jiǎn)單的模型語(yǔ)句。
因此,我們最終的目標(biāo)就是構(gòu)建一個(gè)接口,使其看起來(lái)就像一個(gè)非分布式存儲(chǔ)和計(jì)算系統(tǒng)一樣,但是實(shí)際又是一個(gè)有極高性能和容錯(cuò)性的分布式系統(tǒng)。
關(guān)于抽象接口的落地實(shí)現(xiàn),就不得不提到人們?cè)跇?gòu)建分布式系統(tǒng)時(shí),使用到的很多工具了:
- RPC(remote procedure call) : rpc的目標(biāo)計(jì)算掩蓋我們正在不可靠網(wǎng)絡(luò)上通信的事實(shí)
- 線程 : 使用線程來(lái)充分利用多核心計(jì)算機(jī),同時(shí)線程提供了一種結(jié)構(gòu)化并發(fā)操作方式,可以簡(jiǎn)化并發(fā)操作
- 線程會(huì)導(dǎo)致并發(fā)問題,因此我們需要花費(fèi)一些時(shí)間來(lái)考慮并發(fā)控制,比如鎖
可擴(kuò)展性
我們構(gòu)建分布式系統(tǒng)的初衷是為了追求可擴(kuò)展性,這里可擴(kuò)展性指的是我用一臺(tái)計(jì)算機(jī)解決了一些問題,那么當(dāng)我增加一臺(tái)計(jì)算機(jī)后,我只需一半時(shí)間就可以解決這些問題。也就是說(shuō)我只需要通過增加計(jì)算機(jī)的數(shù)量,系統(tǒng)性能和吞吐量就可以得到對(duì)應(yīng)的提高,而非通過重構(gòu)系統(tǒng)這種高昂花費(fèi)且復(fù)雜的做法。
無(wú)腦堆機(jī)器也未必能解決問題呦 ! 請(qǐng)看下面這個(gè)場(chǎng)景:
在上面的場(chǎng)景中,系統(tǒng)一開始的瓶頸在Web服務(wù)器端產(chǎn)生,但是隨著我們沉迷于堆Web server的快樂中時(shí),系統(tǒng)的瓶頸已經(jīng)悄咪咪轉(zhuǎn)移到了DB端,當(dāng)我們嘗試舊計(jì)重施的時(shí)候,會(huì)發(fā)現(xiàn)DB的拆分?jǐn)U容似乎沒那么容易!
因此傳統(tǒng)的單體數(shù)據(jù)庫(kù)已經(jīng)沒有辦法滿足我們的需求了,我們需要一種能夠通過堆機(jī)器實(shí)現(xiàn)擴(kuò)展的分布式存儲(chǔ)機(jī)制。
可用性(容錯(cuò)性)
大型分布式系統(tǒng)有一個(gè)很大的問題就是一些罕見的問題會(huì)被放大,例如1000臺(tái)計(jì)算機(jī)組成的集群中,總是會(huì)有故障發(fā)生,要么是機(jī)器故障,要么是運(yùn)行出錯(cuò),要么是運(yùn)行緩慢,要么是執(zhí)行錯(cuò)誤的任務(wù),要么是網(wǎng)絡(luò)問題。在一個(gè)大型分布式系統(tǒng)中,總是會(huì)有各種小問題出現(xiàn),所以大型系統(tǒng)會(huì)將一些幾乎不可能發(fā)生的問題,變成一個(gè)持續(xù)不斷的問題。
所以,因?yàn)殄e(cuò)誤總會(huì)發(fā)生,必須要在設(shè)計(jì)時(shí)就考慮,系統(tǒng)能夠屏蔽錯(cuò)誤,或者說(shuō)能夠在出錯(cuò)時(shí)繼續(xù)運(yùn)行。同時(shí),因?yàn)槲覀冃枰獮榈谌綉?yīng)用開發(fā)人員提供方便的抽象接口,我們的確也需要構(gòu)建這樣一種基礎(chǔ)架構(gòu),它能夠盡可能多的對(duì)應(yīng)用開發(fā)人員屏蔽和掩蓋錯(cuò)誤。這樣,應(yīng)用開發(fā)人員就不需要處理各種各樣的可能發(fā)生的錯(cuò)誤。
對(duì)于容錯(cuò),有很多不同的概念可以表述。這些表述中,有一個(gè)共同的思想就是可用性(Availability)。某些系統(tǒng)經(jīng)過精心的設(shè)計(jì),這樣在特定的錯(cuò)誤類型下,系統(tǒng)仍然能夠正常運(yùn)行,仍然可以像沒有出現(xiàn)錯(cuò)誤一樣,為你提供完整的服務(wù)。
某些系統(tǒng)通過這種方式提供可用性。比如,你構(gòu)建了一個(gè)有兩個(gè)拷貝的多副本系統(tǒng),其中一個(gè)故障了,另一個(gè)還能運(yùn)行。當(dāng)然如果兩個(gè)副本都故障了,你的系統(tǒng)就不再有可用性。所以,可用系統(tǒng)通常是指,在特定的故障范圍內(nèi),系統(tǒng)仍然能夠提供服務(wù),系統(tǒng)仍然是可用的。如果出現(xiàn)了更多的故障,系統(tǒng)將不再可用。
除了可用性之外,另一種容錯(cuò)特性是自我可恢復(fù)性(recoverability)。這里的意思是,如果出現(xiàn)了問題,服務(wù)會(huì)停止工作,不再響應(yīng)請(qǐng)求,之后有人來(lái)修復(fù),并且在修復(fù)之后系統(tǒng)仍然可以正常運(yùn)行,就像沒有出現(xiàn)過問題一樣。這是一個(gè)比可用性更弱的需求,因?yàn)樵诔霈F(xiàn)故障到故障組件被修復(fù)期間,系統(tǒng)將會(huì)完全停止工作。但是修復(fù)之后,系統(tǒng)又可以完全正確的重新運(yùn)行,所以可恢復(fù)性是一個(gè)重要的需求。
對(duì)于一個(gè)可恢復(fù)的系統(tǒng),通常需要做一些操作,例如將最新的數(shù)據(jù)存放在磁盤中,這樣在供電恢復(fù)之后(假設(shè)故障就是斷電),才能將這些數(shù)據(jù)取回來(lái)。甚至說(shuō)對(duì)于一個(gè)具備可用性的系統(tǒng),為了讓系統(tǒng)在實(shí)際中具備應(yīng)用意義,也需要具備可恢復(fù)性。因?yàn)榭捎玫南到y(tǒng)僅僅是在一定的故障范圍內(nèi)才可用,如果故障太多,可用系統(tǒng)也會(huì)停止工作,停止一切響應(yīng)。但是當(dāng)足夠的故障被修復(fù)之后,系統(tǒng)還是需要能繼續(xù)工作。所以,一個(gè)好的可用的系統(tǒng),某種程度上應(yīng)該也是可恢復(fù)的。當(dāng)出現(xiàn)太多故障時(shí),系統(tǒng)會(huì)停止響應(yīng),但是修復(fù)之后依然能正確運(yùn)行。這是我們期望看到的。
為了實(shí)現(xiàn)這些特性,有很多工具。其中最重要的有兩個(gè):
-
一個(gè)是非易失存儲(chǔ)(non-volatile storage,類似于硬盤)。這樣當(dāng)出現(xiàn)類似電源故障,甚至整個(gè)機(jī)房的電源都故障時(shí),我們可以使用非易失存儲(chǔ),比如硬盤,閃存,SSD之類的。我們可以存放一些checkpoint或者系統(tǒng)狀態(tài)的log在這些存儲(chǔ)中,這樣當(dāng)備用電源恢復(fù)或者某人修好了電力供給,我們還是可以從硬盤中讀出系統(tǒng)最新的狀態(tài),并從那個(gè)狀態(tài)繼續(xù)運(yùn)行。所以,這里的一個(gè)工具是非易失存儲(chǔ)。因?yàn)楦路且资Т鎯?chǔ)是代價(jià)很高的操作,所以相應(yīng)的出現(xiàn)了很多非易失存儲(chǔ)的管理工具。同時(shí)構(gòu)建一個(gè)高性能,容錯(cuò)的系統(tǒng),聰明的做法是避免頻繁的寫入非易失存儲(chǔ)。在過去,甚至對(duì)于今天的一個(gè)3GHZ的處理器,寫入一個(gè)非易失存儲(chǔ)意味著移動(dòng)磁盤臂并等待磁碟旋轉(zhuǎn),這兩個(gè)過程都非常緩慢。有了閃存會(huì)好很多,但是為了獲取好的性能,仍然需要許多思考。
-
對(duì)于容錯(cuò)的另一個(gè)重要工具是復(fù)制(replication),不過,管理復(fù)制的多副本系統(tǒng)會(huì)有些棘手。任何一個(gè)多副本系統(tǒng)中,都會(huì)有一個(gè)關(guān)鍵的問題,比如說(shuō),我們有兩臺(tái)服務(wù)器,它們本來(lái)應(yīng)該是有著相同的系統(tǒng)狀態(tài),現(xiàn)在的關(guān)鍵問題在于,這兩個(gè)副本總是會(huì)意外的偏離同步的狀態(tài),而不再互為副本。對(duì)于任何一種使用復(fù)制實(shí)現(xiàn)容錯(cuò)的系統(tǒng),我們都面臨這個(gè)問題。lab2和lab3都是通過管理多副本來(lái)實(shí)現(xiàn)容錯(cuò)的系統(tǒng),你將會(huì)看到這里究竟有多復(fù)雜。
一致性
我們通過一個(gè)例子來(lái)理解一致性,假設(shè)我們?cè)跇?gòu)建一個(gè)分布式存儲(chǔ)系統(tǒng),并且這是一個(gè)KV服務(wù)。這個(gè)KV服務(wù)只支持兩種操作:
- 其中一個(gè)是put操作會(huì)將一個(gè)value存入一個(gè)key
- 另一個(gè)是get操作會(huì)取出key對(duì)應(yīng)的value
整體表現(xiàn)就像是一個(gè)大的key-value表單。當(dāng)我需要對(duì)一個(gè)分布式系統(tǒng)舉例時(shí),我總是會(huì)想到KV服務(wù),因?yàn)樗鼈円埠芑A(chǔ),可以算是某種基礎(chǔ)簡(jiǎn)單版本的存儲(chǔ)系統(tǒng)。
現(xiàn)在,如果你是程序員,如果這兩個(gè)操作有特定的意義(或者說(shuō)操作滿足一致性),那么對(duì)于你是有幫助的。你可以去查看手冊(cè),手冊(cè)會(huì)向你解釋,如果你調(diào)用get你會(huì)獲取到什么,如果你調(diào)用put會(huì)有什么效果。如果有這樣的手冊(cè),那是極好的。否則,如果你不知道put/get的實(shí)際行為,你又該如何寫你的應(yīng)用程序呢?
一致性就是用來(lái)定義操作行為的概念。之所以一致性是分布式系統(tǒng)中一個(gè)有趣的話題,是因?yàn)椋瑥男阅芎腿蒎e(cuò)的角度來(lái)說(shuō),我們通常會(huì)有多個(gè)副本。在一個(gè)非分布式系統(tǒng)中,你通常只有一個(gè)服務(wù)器,一個(gè)表單。雖然不是絕對(duì),但是通常來(lái)說(shuō)對(duì)于put/get的行為不會(huì)有歧義。直觀上來(lái)說(shuō),put就是更新這個(gè)表單,get就是從表單中獲取當(dāng)前表單中存儲(chǔ)的數(shù)據(jù)。但是在一個(gè)分布式系統(tǒng)中,由于復(fù)制或者緩存,數(shù)據(jù)可能存在于多個(gè)副本當(dāng)中,于是就有了多個(gè)不同版本的key-value對(duì)。假設(shè)服務(wù)器有兩個(gè)副本,那么他們都有一個(gè)key-value表單,兩個(gè)表單中key 1對(duì)應(yīng)的值都是20。
現(xiàn)在某個(gè)客戶端發(fā)送了一個(gè)put請(qǐng)求,并希望將key 1改成值21。這里或許是KV服務(wù)里面的一個(gè)計(jì)數(shù)器。這個(gè)put請(qǐng)求發(fā)送給了第一臺(tái)服務(wù)器:
之后會(huì)發(fā)送給第二臺(tái)服務(wù)器,因?yàn)橄嗤膒ut請(qǐng)求需要發(fā)送給兩個(gè)副本,這樣這兩個(gè)副本才能保持同步。但是就在客戶端準(zhǔn)備給第二臺(tái)服務(wù)器發(fā)送相同請(qǐng)求時(shí),這個(gè)客戶端故障了,可能是電源故障或者操作系統(tǒng)的bug之類的。所以,現(xiàn)在我們處于一個(gè)不好的狀態(tài),我們發(fā)送了一個(gè)put請(qǐng)求,更新了一個(gè)副本的值是21,但是另一個(gè)副本的值仍然是20。
如果現(xiàn)在某人通過get讀取key為1的值,那么他可能獲得21,也可能獲得20,取決于get請(qǐng)求發(fā)送到了哪個(gè)服務(wù)器。即使規(guī)定了總是把請(qǐng)求先發(fā)送給第一個(gè)服務(wù)器,那么我們?cè)跇?gòu)建容錯(cuò)系統(tǒng)時(shí),如果第一臺(tái)服務(wù)器故障了,請(qǐng)求也會(huì)發(fā)給第二臺(tái)服務(wù)器。所以不管怎么樣,總有一天你會(huì)面臨暴露舊數(shù)據(jù)的風(fēng)險(xiǎn)。很可能是這樣,最開始許多get請(qǐng)求都得到了21,之后過了一周突然一些get請(qǐng)求得到了一周之前的舊數(shù)據(jù)(20)。所以,這里不是很一致。并且,如果我們不小心的話,這個(gè)場(chǎng)景是可能發(fā)生的。所以,我們需要確定put/get操作的一些規(guī)則。
實(shí)際上,對(duì)于一致性有很多不同的定義。有一些非常直觀,比如說(shuō)get請(qǐng)求可以得到最近一次完成的put請(qǐng)求寫入的值。這種一般也被稱為強(qiáng)一致(Strong Consistency)。但是,事實(shí)上,構(gòu)建一個(gè)弱一致的系統(tǒng)也是非常有用的。弱一致是指,不保證get請(qǐng)求可以得到最近一次完成的put請(qǐng)求寫入的值。盡管有很多細(xì)節(jié)的工作要處理,強(qiáng)一致可以保證get得到的是put寫入的最新的數(shù)據(jù);而很多的弱一致系統(tǒng)不會(huì)做出類似的保證。所以在一個(gè)弱一致系統(tǒng)中,某人通過put請(qǐng)求寫入了一個(gè)數(shù)據(jù),但是你通過get看到的可能仍然是一個(gè)舊數(shù)據(jù),而這個(gè)舊數(shù)據(jù)可能是很久之前寫入的。
人們對(duì)于弱一致感興趣的原因是,雖然強(qiáng)一致可以確保get獲取的是最新的數(shù)據(jù),但是實(shí)現(xiàn)這一點(diǎn)的代價(jià)非常高。幾乎可以確定的是,分布式系統(tǒng)的各個(gè)組件需要做大量的通信,才能實(shí)現(xiàn)強(qiáng)一致性。如果你有多個(gè)副本,那么不管get還是put都需要詢問每一個(gè)副本。在之前的例子中,客戶端在更新的過程中故障了,導(dǎo)致一個(gè)副本更新了,而另一個(gè)副本沒有更新。如果我們要實(shí)現(xiàn)強(qiáng)一致,簡(jiǎn)單的方法就是同時(shí)讀兩個(gè)副本,如果有多個(gè)副本就讀取所有的副本,并使用最近一次寫入的數(shù)據(jù)。但是這樣的代價(jià)很高,因?yàn)樾枰罅康耐ㄐ挪拍艿玫揭粋€(gè)數(shù)據(jù)。所以,為了盡可能的避免通信,尤其當(dāng)副本相隔的很遠(yuǎn)的時(shí)候,人們會(huì)構(gòu)建弱一致系統(tǒng),并允許讀取出舊的數(shù)據(jù)。當(dāng)然,為了讓弱一致更有實(shí)際意義,人們還會(huì)定義更多的規(guī)則。
強(qiáng)一致帶來(lái)的昂貴的通信問題,會(huì)把你帶入這樣的困境:當(dāng)我們使用多副本來(lái)完成容錯(cuò)時(shí),我們的確需要每個(gè)副本都有獨(dú)立的出錯(cuò)概率,這樣故障才不會(huì)關(guān)聯(lián)。例如,將兩個(gè)副本放在一個(gè)機(jī)房的一個(gè)機(jī)架上,是一個(gè)非常糟糕的主意。如果有誰(shuí)踢到了機(jī)架的電源線,那我們數(shù)據(jù)的兩個(gè)副本都沒了,因?yàn)樗鼈兌歼B在同一個(gè)機(jī)架的同一根電線上。所以,為了使副本的錯(cuò)誤域盡可能獨(dú)立,為了獲得良好的容錯(cuò)特性,人們希望將不同的副本放置在盡可能遠(yuǎn)的位置,例如在不同的城市或者在大陸的兩端。這樣,如果地震摧毀了一個(gè)數(shù)據(jù)中心,另一個(gè)數(shù)據(jù)中心中的副本有很大可能還能保留。我們期望這樣的效果。但是如果我們這么做了,另一個(gè)副本可能在數(shù)千英里之外,按照光速來(lái)算,也需要花費(fèi)幾毫秒到幾十毫秒才能完成橫跨洲際的數(shù)據(jù)通信,而這只是為了更新數(shù)據(jù)的另一個(gè)副本。所以,為了保持強(qiáng)一致的通信,代價(jià)可能會(huì)非常高。因?yàn)槊看文銏?zhí)行put或者get請(qǐng)求,你都需要等待幾十毫秒來(lái)與數(shù)據(jù)的兩個(gè)副本通信,以確保它們都被更新了或者都被檢查了以獲得最新的數(shù)據(jù)?,F(xiàn)在的處理器每秒可以執(zhí)行數(shù)十億條指令,等待幾十毫秒會(huì)大大影響系統(tǒng)的處理速度。
所以,人們常常會(huì)使用弱一致系統(tǒng),你只需要更新最近的數(shù)據(jù)副本,并且只需要從最近的副本獲取數(shù)據(jù)。在學(xué)術(shù)界和現(xiàn)實(shí)世界(工業(yè)界),有大量關(guān)于構(gòu)建弱一致性保證的研究。所以,弱一致對(duì)于應(yīng)用程序來(lái)說(shuō)很有用,并且它可以用來(lái)獲取高的性能。
MapReduce
MapReduce是由Google設(shè)計(jì),開發(fā)和使用的一個(gè)系統(tǒng),相關(guān)的論文在2004年發(fā)表。Google當(dāng)時(shí)面臨的問題是,他們需要在TB級(jí)別的數(shù)據(jù)上進(jìn)行大量的計(jì)算。比如說(shuō),為所有的網(wǎng)頁(yè)創(chuàng)建索引,分析整個(gè)互聯(lián)網(wǎng)的鏈接路徑并得出最重要或者最權(quán)威的網(wǎng)頁(yè)。如你所知,在當(dāng)時(shí),整個(gè)互聯(lián)網(wǎng)的數(shù)據(jù)也有數(shù)十TB。構(gòu)建索引基本上等同于對(duì)整個(gè)數(shù)據(jù)做排序,而排序比較費(fèi)時(shí)。如果用一臺(tái)計(jì)算機(jī)對(duì)整個(gè)互聯(lián)網(wǎng)數(shù)據(jù)進(jìn)行排序,要花費(fèi)多長(zhǎng)時(shí)間呢?可能要幾周,幾個(gè)月,甚至幾年。所以,當(dāng)時(shí)Google非常希望能將對(duì)大量數(shù)據(jù)的大量運(yùn)算并行跑在幾千臺(tái)計(jì)算機(jī)上,這樣才能快速完成計(jì)算。對(duì)Google來(lái)說(shuō),購(gòu)買大量的計(jì)算機(jī)是沒問題的,這樣Google的工程師就不用花大量時(shí)間來(lái)看報(bào)紙來(lái)等他們的大型計(jì)算任務(wù)完成。所以,有段時(shí)間,Google買了大量的計(jì)算機(jī),并讓它的聰明的工程師在這些計(jì)算機(jī)上編寫分布式軟件,這樣工程師們可以將手頭的問題分包到大量計(jì)算機(jī)上去完成,管理這些運(yùn)算,并將數(shù)據(jù)取回。
如果你只雇傭熟練的分布式系統(tǒng)專家作為工程師,盡管可能會(huì)有些浪費(fèi),也是可以的。但是Google想雇用的是各方面有特長(zhǎng)的人,不一定是想把所有時(shí)間都花在編寫分布式軟件上的工程師。所以Google需要一種框架,可以讓它的工程師能夠進(jìn)行任意的數(shù)據(jù)分析,例如排序,網(wǎng)絡(luò)索引器,鏈接分析器以及任何的運(yùn)算。工程師只需要實(shí)現(xiàn)應(yīng)用程序的核心,就能將應(yīng)用程序運(yùn)行在數(shù)千臺(tái)計(jì)算機(jī)上,而不用考慮如何將運(yùn)算工作分發(fā)到數(shù)千臺(tái)計(jì)算機(jī),如何組織這些計(jì)算機(jī),如何移動(dòng)數(shù)據(jù),如何處理故障等等這些細(xì)節(jié)。所以,當(dāng)時(shí)Google需要一種框架,使得普通工程師也可以很容易的完成并運(yùn)行大規(guī)模的分布式運(yùn)算。這就是MapReduce出現(xiàn)的背景。
MapReduce的思想是,應(yīng)用程序設(shè)計(jì)人員和分布式運(yùn)算的使用者,只需要寫簡(jiǎn)單的Map函數(shù)和Reduce函數(shù),而不需要知道任何有關(guān)分布式的事情,MapReduce框架會(huì)處理剩下的事情。
抽象來(lái)看,MapReduce假設(shè)有一些輸入,這些輸入被分割成大量的不同的文件或者數(shù)據(jù)塊。所以,我們假設(shè)現(xiàn)在有輸入文件1,輸入文件2和輸入文件3,這些輸入可能是從網(wǎng)上抓取的網(wǎng)頁(yè),更可能是包含了大量網(wǎng)頁(yè)的文件。
MapReduce啟動(dòng)時(shí),會(huì)查找Map函數(shù)。之后,MapReduce框架會(huì)為每個(gè)輸入文件運(yùn)行Map函數(shù)。這里很明顯有一些可以并行運(yùn)算的地方,比如說(shuō)可以并行運(yùn)行多個(gè)只關(guān)注輸入和輸出的Map函數(shù)。
Map函數(shù)以文件作為輸入,文件又是整個(gè)輸入數(shù)據(jù)的一部分。Map函數(shù)的輸出是一個(gè)key-value對(duì)的列表。假設(shè)我們?cè)趯?shí)現(xiàn)一個(gè)最簡(jiǎn)單的MapReduce Job:?jiǎn)卧~計(jì)數(shù)器。它會(huì)統(tǒng)計(jì)每個(gè)單詞出現(xiàn)的次數(shù)。在這個(gè)例子中,Map函數(shù)會(huì)輸出key-value對(duì),其中key是單詞,而value是1。Map函數(shù)會(huì)將輸入中的每個(gè)單詞拆分,并輸出一個(gè)key-value對(duì),key是該單詞,value是1。最后需要對(duì)所有的key-value進(jìn)行計(jì)數(shù),以獲得最終的輸出。所以,假設(shè)輸入文件1包含了單詞a和單詞b,Map函數(shù)的輸出將會(huì)是key=a,value=1和key=b,value=1。第二個(gè)Map函數(shù)只從輸入文件2看到了b,那么輸出將會(huì)是key=b,value=1。第三個(gè)輸入文件有一個(gè)a和一個(gè)c。
我們對(duì)所有的輸入文件都運(yùn)行了Map函數(shù),并得到了論文中稱之為中間輸出(intermediate output),也就是每個(gè)Map函數(shù)輸出的key-value對(duì)。
運(yùn)算的第二階段是運(yùn)行Reduce函數(shù)。MapReduce框架會(huì)收集所有Map函數(shù)輸出的每一個(gè)單詞的統(tǒng)計(jì)。比如說(shuō),MapReduce框架會(huì)先收集每一個(gè)Map函數(shù)輸出的key為a的key-value對(duì)。收集了之后,會(huì)將它們提交給Reduce函數(shù)。
之后會(huì)收集所有的b。這里的收集是真正意義上的收集,因?yàn)閎是由不同計(jì)算機(jī)上的不同Map函數(shù)生成,所以不僅僅是數(shù)據(jù)從一臺(tái)計(jì)算機(jī)移動(dòng)到另一臺(tái)(如果Map只在一臺(tái)計(jì)算機(jī)的一個(gè)實(shí)例里,可以直接通過一個(gè)RPC將數(shù)據(jù)從Map移到Reduce)。我們收集所有的b,并將它們提交給另一個(gè)Reduce函數(shù)。這個(gè)Reduce函數(shù)的入?yún)⑹撬械膋ey為b的key-value對(duì)。對(duì)c也是一樣。所以,MapReduce框架會(huì)為所有Map函數(shù)輸出的每一個(gè)key,調(diào)用一次Reduce函數(shù)。
在我們這個(gè)簡(jiǎn)單的單詞計(jì)數(shù)器的例子中,Reduce函數(shù)只需要統(tǒng)計(jì)傳入?yún)?shù)的長(zhǎng)度,甚至都不用查看傳入?yún)?shù)的具體內(nèi)容,因?yàn)槊恳粋€(gè)傳入?yún)?shù)代表對(duì)單詞加1,而我們只需要統(tǒng)計(jì)個(gè)數(shù)。最后,每個(gè)Reduce都輸出與其關(guān)聯(lián)的單詞和這個(gè)單詞的數(shù)量。所以第一個(gè)Reduce輸出a=2,第二個(gè)Reduce輸出b=2,第三個(gè)Reduce輸出c=1。
這就是一個(gè)典型的MapReduce Job。從整體來(lái)看,為了保證完整性,有一些術(shù)語(yǔ)要介紹一下:
- Job。整個(gè)MapReduce計(jì)算稱為Job。
- Task。每一次MapReduce調(diào)用稱為Task。
所以,對(duì)于一個(gè)完整的MapReduce Job,它由一些Map Task和一些Reduce Task組成。所以這是一個(gè)單詞計(jì)數(shù)器的例子,它解釋了MapReduce的基本工作方式。
Map函數(shù)和Reduce函數(shù)
Map函數(shù)使用一個(gè)key和一個(gè)value作為參數(shù)。我們這里說(shuō)的函數(shù)是由普通編程語(yǔ)言編寫,例如C++,Java等,所以這里的函數(shù)任何人都可以寫出來(lái)。入?yún)⒅?,key是輸入文件的名字,通常會(huì)被忽略,因?yàn)槲覀儾惶P(guān)心文件名是什么,value是輸入文件的內(nèi)容。所以,對(duì)于一個(gè)單詞計(jì)數(shù)器來(lái)說(shuō),value包含了要統(tǒng)計(jì)的文本,我們會(huì)將這個(gè)文本拆分成單詞。之后對(duì)于每一個(gè)單詞,我們都會(huì)調(diào)用emit。emit由MapReduce框架提供,并且這里的emit屬于Map函數(shù)。emit會(huì)接收兩個(gè)參數(shù),其中一個(gè)是key,另一個(gè)是value。在單詞計(jì)數(shù)器的例子中,emit入?yún)⒌膋ey是單詞,value是字符串“1”。這就是一個(gè)Map函數(shù)。在一個(gè)單詞計(jì)數(shù)器的MapReduce Job中,Map函數(shù)實(shí)際就可以這么簡(jiǎn)單。而這個(gè)Map函數(shù)不需要知道任何分布式相關(guān)的信息,不需要知道有多臺(tái)計(jì)算機(jī),不需要知道實(shí)際會(huì)通過網(wǎng)絡(luò)來(lái)移動(dòng)數(shù)據(jù)。這里非常直觀。
def map_function(key, value):
words = split_text_into_words(value)
for word in words:
emit(word, "1") # 將每個(gè)單詞作為key,固定的值"1"作為value,生成鍵值對(duì)
Reduce函數(shù)的入?yún)⑹悄硞€(gè)特定key的所有實(shí)例(Map輸出中的key-value對(duì)中,出現(xiàn)了一次特定的key就可以算作一個(gè)實(shí)例)。所以Reduce函數(shù)也是使用一個(gè)key和一個(gè)value作為參數(shù),其中value是一個(gè)數(shù)組,里面每一個(gè)元素是Map函數(shù)輸出的key的一個(gè)實(shí)例的value。對(duì)于單詞計(jì)數(shù)器來(lái)說(shuō),key就是單詞,value就是由字符串“1”組成的數(shù)組,所以,我們不需要關(guān)心value的內(nèi)容是什么,我們只需要關(guān)心value數(shù)組的長(zhǎng)度。Reduce函數(shù)也有一個(gè)屬于自己的emit函數(shù)。這里的emit函數(shù)只會(huì)接受一個(gè)參數(shù)value,這個(gè)value會(huì)作為Reduce函數(shù)入?yún)⒌膋ey的最終輸出。所以,對(duì)于單詞計(jì)數(shù)器,我們會(huì)給emit傳入數(shù)組的長(zhǎng)度。這就是一個(gè)最簡(jiǎn)單的Reduce函數(shù)。并且Reduce也不需要知道任何有關(guān)容錯(cuò)或者其他有關(guān)分布式相關(guān)的信息。
def reduce_function(key, values):
count = sum(values) # 對(duì)數(shù)組中的值("1")進(jìn)行累加
emit(key, count) # 輸出單詞及其出現(xiàn)的總次數(shù)
疑問
可以將Reduce函數(shù)的輸出再傳遞給Map函數(shù)嗎?
- 在現(xiàn)實(shí)中,這是很常見的。MapReduce用戶定義了一個(gè)MapReduce Job,接收一些輸入,生成一些輸出。之后可能會(huì)有第二個(gè)MapReduce Job來(lái)消費(fèi)前一個(gè)Job的輸出。
- 對(duì)于一些非常復(fù)雜的多階段分析或者迭代算法,比如說(shuō)Google用來(lái)評(píng)價(jià)網(wǎng)頁(yè)的重要性和影響力的PageRank算法,這些算法是逐漸向答案收斂的。我認(rèn)為Google最初就是這么使用MapReduce的,他們運(yùn)行MapReduce Job多次,每一次的輸出都是一個(gè)網(wǎng)頁(yè)的列表,其中包含了網(wǎng)頁(yè)的價(jià)值,權(quán)重或者重要性。所以將MapReduce的輸出作為另一個(gè)MapReduce Job的輸入這很正常。
如果可以將Reduce的輸出作為Map的輸入,在生成Reduce函數(shù)的輸出時(shí)需要有什么注意嗎?
- 是的,你需要設(shè)置一些內(nèi)容。比如你需要這么寫Reduce函數(shù),使其在某種程度上知道應(yīng)該按照下一個(gè)MapReduce Job需要的格式生成數(shù)據(jù)。這里實(shí)際上帶出了一些MapReduce框架的缺點(diǎn)。如果你的算法可以很簡(jiǎn)單的由Map函數(shù)、Map函數(shù)的中間輸出以及Reduce函數(shù)來(lái)表達(dá),那是極好的。
- MapReduce對(duì)于能夠套用這種形式的算法是極好的。并且,Map函數(shù)必須是完全獨(dú)立的,它們是一些只關(guān)心入?yún)⒌暮瘮?shù)。這里就有一些限制了。事實(shí)上,很多人想要的更長(zhǎng)的運(yùn)算流程,這涉及到不同的處理。使用MapReduce的話,你不得不將多個(gè)MapReduce Job拼裝在一起。而在本課程后面會(huì)介紹的一些更高級(jí)的系統(tǒng)中,會(huì)讓你指定完整的計(jì)算流程,然后這些系統(tǒng)會(huì)做優(yōu)化。這些系統(tǒng)會(huì)發(fā)現(xiàn)所有你想完成的工作,然后有效的組織更復(fù)雜的計(jì)算。
MapReduce框架更重要還是Map/Reduce函數(shù)更重要?
- 從程序員的角度來(lái)看,只需要關(guān)心Map函數(shù)和Reduce函數(shù)。從我們的角度來(lái)看,我們需要關(guān)心的是worker進(jìn)程和worker服務(wù)器。這些是MapReduce框架的一部分,它們與其它很多組件一起調(diào)用了Map函數(shù)和Reduce函數(shù)。所以是的,從我們的角度來(lái)看,我們更關(guān)心框架是如何組成的。從程序員的角度來(lái)看,所有的分布式的內(nèi)容都被剝離了。
當(dāng)你調(diào)用emit時(shí),數(shù)據(jù)會(huì)發(fā)生什么變化?emit函數(shù)在哪運(yùn)行?
-
首先看,這些函數(shù)在哪運(yùn)行。如MapReduce論文的圖1所示:
-
現(xiàn)實(shí)中,MapReduce運(yùn)行在大量的服務(wù)器之上,我們稱之為worker服務(wù)器或者worker。同時(shí),也會(huì)有一個(gè)Master節(jié)點(diǎn)來(lái)組織整個(gè)計(jì)算過程。這里實(shí)際發(fā)生的是,Master服務(wù)器知道有多少輸入文件,例如5000個(gè)輸入文件,之后它將Map函數(shù)分發(fā)到不同的worker。所以,它會(huì)向worker服務(wù)器發(fā)送一條消息說(shuō),請(qǐng)對(duì)這個(gè)輸入文件執(zhí)行Map函數(shù)吧。之后,MapReduce框架中的worker進(jìn)程會(huì)讀取文件的內(nèi)容,調(diào)用Map函數(shù)并將文件名和文件內(nèi)容作為參數(shù)傳給Map函數(shù)。worker進(jìn)程還需要實(shí)現(xiàn)emit,這樣,每次Map函數(shù)調(diào)用emit,worker進(jìn)程就會(huì)將數(shù)據(jù)寫入到本地磁盤的文件中。所以,Map函數(shù)中調(diào)用emit的效果是在worker的本地磁盤上創(chuàng)建文件,這些文件包含了當(dāng)前worker的Map函數(shù)生成的所有的key和value。
-
所以,Map階段結(jié)束時(shí),我們看到的就是Map函數(shù)在worker上生成的一些文件。之后,MapReduce的worker會(huì)將這些數(shù)據(jù)移動(dòng)到Reduce所需要的位置。對(duì)于一個(gè)典型的大型運(yùn)算,Reduce的入?yún)怂蠱ap函數(shù)對(duì)于特定key的輸出。通常來(lái)說(shuō),每個(gè)Map函數(shù)都可能生成大量key。所以通常來(lái)說(shuō),在運(yùn)行Reduce函數(shù)之前。運(yùn)行在MapReduce的worker服務(wù)器上的進(jìn)程需要與集群中每一個(gè)其他服務(wù)器交互來(lái)詢問說(shuō),看,我需要對(duì)key=a運(yùn)行Reduce,請(qǐng)看一下你本地磁盤中存儲(chǔ)的Map函數(shù)的中間輸出,找出所有key=a,并通過網(wǎng)絡(luò)將它們發(fā)給我。所以,Reduce worker需要從每一個(gè)worker獲取特定key的實(shí)例。這是通過由Master通知到Reduce worker的一條指令來(lái)觸發(fā)。一旦worker收集完所有的數(shù)據(jù),它會(huì)調(diào)用Reduce函數(shù),Reduce函數(shù)運(yùn)算完了會(huì)調(diào)用自己的emit,這個(gè)emit與Map函數(shù)中的emit不一樣,它會(huì)將輸出寫入到一個(gè)Google使用的共享文件服務(wù)中。
-
有關(guān)輸入和輸出文件的存放位置,這是我之前沒有提到的,它們都存放在文件中,但是因?yàn)槲覀兿胍`活的在任意的worker上讀取任意的數(shù)據(jù),這意味著我們需要某種網(wǎng)絡(luò)文件系統(tǒng)(network file system)來(lái)存放輸入數(shù)據(jù)。所以實(shí)際上,MapReduce論文談到了GFS(Google File System)。GFS是一個(gè)共享文件服務(wù),并且它也運(yùn)行在MapReduce的worker集群的物理服務(wù)器上。GFS會(huì)自動(dòng)拆分你存儲(chǔ)的任何大文件,并且以64MB的塊存儲(chǔ)在多個(gè)服務(wù)器之上。所以,如果你有了10TB的網(wǎng)頁(yè)數(shù)據(jù),你只需要將它們寫入到GFS,甚至你寫入的時(shí)候是作為一個(gè)大文件寫入的,GFS會(huì)自動(dòng)將這個(gè)大文件拆分成64MB的塊,并將這些塊平均的分布在所有的GFS服務(wù)器之上,而這是極好的,這正是我們所需要的。如果我們接下來(lái)想要對(duì)剛剛那10TB的網(wǎng)頁(yè)數(shù)據(jù)運(yùn)行MapReduce Job,數(shù)據(jù)已經(jīng)均勻的分割存儲(chǔ)在所有的服務(wù)器上了。如果我們有1000臺(tái)服務(wù)器,我們會(huì)啟動(dòng)1000個(gè)Map worker,每個(gè)Map worker會(huì)讀取1/1000輸入數(shù)據(jù)。這些Map worker可以并行的從1000個(gè)GFS文件服務(wù)器讀取數(shù)據(jù),并獲取巨大的讀取吞吐量,也就是1000臺(tái)服務(wù)器能提供的吞吐量。
這里的箭頭代表什么意思?
- 隨著Google這些年對(duì)MapReduce系統(tǒng)的改進(jìn),答案也略有不同。通常情況下,如果我們?cè)谝粋€(gè)例如GFS的文件系統(tǒng)中存儲(chǔ)大的文件,你的數(shù)據(jù)分散在大量服務(wù)器之上,你需要通過網(wǎng)絡(luò)與這些服務(wù)器通信以獲取你的數(shù)據(jù)。在這種情況下,這個(gè)箭頭表示MapReduce的worker需要通過網(wǎng)絡(luò)與存儲(chǔ)了輸入文件的GFS服務(wù)器通信,并通過網(wǎng)絡(luò)將數(shù)據(jù)讀取到MapReduce的worker節(jié)點(diǎn),進(jìn)而將數(shù)據(jù)傳遞給Map函數(shù)。這是最常見的情況。并且這是MapReduce論文中介紹的工作方式。但是如果你這么做了,這里就有很多網(wǎng)絡(luò)通信。 如果數(shù)據(jù)總共是10TB,那么相應(yīng)的就需要在數(shù)據(jù)中心網(wǎng)絡(luò)上移動(dòng)10TB的數(shù)據(jù)。而數(shù)據(jù)中心網(wǎng)絡(luò)通常是GB級(jí)別的帶寬,所以移動(dòng)10TB的數(shù)據(jù)需要大量的時(shí)間。在論文發(fā)表的2004年,MapReduce系統(tǒng)最大的限制瓶頸是網(wǎng)絡(luò)吞吐。如果你讀到了論文的評(píng)估部分,你會(huì)發(fā)現(xiàn),當(dāng)時(shí)運(yùn)行在一個(gè)有數(shù)千臺(tái)機(jī)器的網(wǎng)絡(luò)上,每臺(tái)計(jì)算機(jī)都接入到一個(gè)機(jī)架,機(jī)架上有以太網(wǎng)交換機(jī),機(jī)架之間通過root交換機(jī)連接(最上面那個(gè)交換機(jī))。
- 如果隨機(jī)的選擇MapReduce的worker服務(wù)器和GFS服務(wù)器,那么至少有一半的機(jī)會(huì),它們之間的通信需要經(jīng)過root交換機(jī),而這個(gè)root交換機(jī)的吞吐量總是固定的。如果做一個(gè)除法,root交換機(jī)的總吞吐除以2000,那么每臺(tái)機(jī)器只能分到50Mb/S的網(wǎng)絡(luò)容量。這個(gè)網(wǎng)絡(luò)容量相比磁盤或者CPU的速度來(lái)說(shuō),要小得多。所以,50Mb/S是一個(gè)巨大的限制。
- 在MapReduce論文中,討論了大量的避免使用網(wǎng)絡(luò)的技巧。其中一個(gè)是將GFS和MapReduce混合運(yùn)行在一組服務(wù)器上。所以如果有1000臺(tái)服務(wù)器,那么GFS和MapReduce都運(yùn)行在那1000臺(tái)服務(wù)器之上。當(dāng)MapReduce的Master節(jié)點(diǎn)拆分Map任務(wù)并分包到不同的worker服務(wù)器上時(shí),Master節(jié)點(diǎn)會(huì)找出輸入文件具體存在哪臺(tái)GFS服務(wù)器上,并把對(duì)應(yīng)于那個(gè)輸入文件的Map Task調(diào)度到同一臺(tái)服務(wù)器上。所以,默認(rèn)情況下,這里的箭頭是指讀取本地文件,而不會(huì)涉及網(wǎng)絡(luò)。雖然由于故障,負(fù)載或者其他原因,不能總是讓Map函數(shù)都讀取本地文件,但是幾乎所有的Map函數(shù)都會(huì)運(yùn)行在存儲(chǔ)了數(shù)據(jù)的相同機(jī)器上,并因此節(jié)省了大量的時(shí)間,否則通過網(wǎng)絡(luò)來(lái)讀取輸入數(shù)據(jù)將會(huì)耗費(fèi)大量的時(shí)間。
- 我之前提過,Map函數(shù)會(huì)將輸出存儲(chǔ)到機(jī)器的本地磁盤,所以存儲(chǔ)Map函數(shù)的輸出不需要網(wǎng)絡(luò)通信,至少不需要實(shí)時(shí)的網(wǎng)絡(luò)通信。但是,我們可以確定的是,為了收集所有特定key的輸出,并將它們傳遞給某個(gè)機(jī)器的Reduce函數(shù),還是需要網(wǎng)絡(luò)通信。假設(shè)現(xiàn)在我們想要讀取所有的相關(guān)數(shù)據(jù),并通過網(wǎng)絡(luò)將這些數(shù)據(jù)傳遞給單臺(tái)機(jī)器,數(shù)據(jù)最開始在運(yùn)行Map Task的機(jī)器上按照行存儲(chǔ)(例如第一行代表第一個(gè)Map函數(shù)輸出a=1,b=1),
- 論文里稱這種數(shù)據(jù)轉(zhuǎn)換之為洗牌(shuffle)。所以,這里確實(shí)需要將每一份數(shù)據(jù)都通過網(wǎng)絡(luò)從創(chuàng)建它的Map節(jié)點(diǎn)傳輸?shù)叫枰腞educe節(jié)點(diǎn)。所以,這也是MapReduce中代價(jià)較大的一部分。
是否可以通過Streaming的方式加速Reduce的讀???
- 你是對(duì)的。你可以設(shè)想一個(gè)不同的定義,其中Reduce通過streaming方式讀取數(shù)據(jù)。我沒有仔細(xì)想過這個(gè)方法,我也不知道這是否可行。作為一個(gè)程序接口,MapReduce的第一目標(biāo)就是讓人們能夠簡(jiǎn)單的編程,人們不需要知道MapReduce里面發(fā)生了什么。對(duì)于一個(gè)streaming方式的Reduce函數(shù),或許就沒有之前的定義那么簡(jiǎn)單了。
- 不過或許可以這么做。實(shí)際上,很多現(xiàn)代的系統(tǒng)中,會(huì)按照streaming的方式處理數(shù)據(jù),而不是像MapReduce那樣通過批量的方式處理Reduce函數(shù)。在MapReduce中,需要一直要等到所有的數(shù)據(jù)都獲取到了才會(huì)進(jìn)行Reduce處理,所以這是一種批量處理?,F(xiàn)代系統(tǒng)通常會(huì)使用streaming并且效率會(huì)高一些。
所以這里的shuffle的重點(diǎn)是,這里實(shí)際上可能會(huì)有大量的網(wǎng)絡(luò)通信。假設(shè)你在進(jìn)行排序,排序的輸入輸出會(huì)有相同的大小。這樣,如果你的輸入是10TB,為了能排序,你需要將10TB的數(shù)據(jù)在網(wǎng)絡(luò)上移動(dòng),并且輸出也會(huì)是10TB,所以這里有大量的數(shù)據(jù)。這可能發(fā)生在任何MapReduce job中,盡管有一些MapReduce job在不同階段的數(shù)據(jù)沒有那么大。
之前有人提過,想將Reduce的輸出傳給另一個(gè)MapReduce job,而這也是人們常做的事情。在一些場(chǎng)景中,Reduce的輸出可能會(huì)非常巨大,比如排序,比如網(wǎng)頁(yè)索引器。10TB的輸入對(duì)應(yīng)的是10TB的輸出。所以,Reduce的輸出也會(huì)存儲(chǔ)在GFS上。但是Reduce只會(huì)生成key-value對(duì),MapReduce框架會(huì)收集這些數(shù)據(jù),并將它們寫入到GFS的大文件中。所以,這里有需要一大輪的網(wǎng)絡(luò)通信,將每個(gè)Reduce的輸出傳輸?shù)较鄳?yīng)的GFS服務(wù)器上。你或許會(huì)認(rèn)為,這里會(huì)使用相同的技巧,就將Reduce的輸出存儲(chǔ)在運(yùn)行了Reduce Task的同一個(gè)GFS服務(wù)器上(因?yàn)槭腔觳康模??;蛟SGoogle這么做了,但是因?yàn)镚FS會(huì)將數(shù)據(jù)做拆分,并且為了提高性能并保留容錯(cuò)性,數(shù)據(jù)會(huì)有2-3份副本。這意味著,不論你寫什么,你總是需要通過網(wǎng)絡(luò)將一份數(shù)據(jù)拷貝寫到2-3臺(tái)服務(wù)器上。所以,這里會(huì)有大量的網(wǎng)絡(luò)通信。這里的網(wǎng)絡(luò)通信,是2004年限制MapReduce的瓶頸。在2020年,因?yàn)橹暗木W(wǎng)絡(luò)架構(gòu)成為了人們想在數(shù)據(jù)中心中做的很多事情的限制因素,現(xiàn)代數(shù)據(jù)中心中,root交換機(jī)比過去快了很多。并且,你或許已經(jīng)見過,一個(gè)典型的現(xiàn)代數(shù)據(jù)中心網(wǎng)絡(luò),會(huì)有很多的root交換機(jī)而不是一個(gè)交換機(jī)(spine-leaf架構(gòu))。每個(gè)機(jī)架交換機(jī)都與每個(gè)root交換機(jī)相連,網(wǎng)絡(luò)流量在多個(gè)root交換機(jī)之間做負(fù)載分擔(dān)。所以,現(xiàn)代數(shù)據(jù)中心網(wǎng)絡(luò)的吞吐大多了。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-627491.html
我認(rèn)為Google幾年前就不再使用MapReduce了,不過在那之前,現(xiàn)代的MapReduce已經(jīng)不再嘗試在GFS數(shù)據(jù)存儲(chǔ)的服務(wù)器上運(yùn)行Map函數(shù)了,它樂意從任何地方加載數(shù)據(jù),因?yàn)榫W(wǎng)絡(luò)已經(jīng)足夠快了。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-627491.html
到了這里,關(guān)于MIT 6.824 -- MapReduce -- 01的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!