騰訊分布式數(shù)據(jù)倉庫(Tencent distributed Data Warehouse, 簡稱TDW)基于開源軟件Hadoop和Hive進行構(gòu)建蚯妇,并且根據(jù)公司數(shù)據(jù)量大陵吸、計算復(fù)雜等特定情況進行了大量優(yōu)化和改造蜒蕾,目前單集群最大規(guī)模達到5600臺薇芝,每日作業(yè)數(shù)達到100多萬茫死,已經(jīng)成為公司最大的離線數(shù)據(jù)處理平臺路翻。為了滿足用戶更加多樣的計算需求狈癞,TDW也在向?qū)崟r化方向發(fā)展,為用戶提供更加高效茂契、穩(wěn)定蝶桶、豐富的服務(wù)。
TDW計算引擎包括兩部分:一個是偏離線的MapReduce掉冶,一個是偏實時的Spark真竖,兩者內(nèi)部都包含了一個重要的過程——Shuffle脐雪。本文對Shuffle過程進行解析,并對兩個計算引擎的Shuffle過程進行比較恢共,對后續(xù)的優(yōu)化方向進行思考和探索战秋,期待經(jīng)過我們不斷的努力,TDW計算引擎運行地更好讨韭。
Shuffle過程介紹
MapReduce的Shuffle過程介紹
Shuffle的本義是洗牌脂信、混洗,把一組有一定規(guī)則的數(shù)據(jù)盡量轉(zhuǎn)換成一組無規(guī)則的數(shù)據(jù)透硝,越隨機越好狰闪。MapReduce中的Shuffle更像是洗牌的逆過程,把一組無規(guī)則的數(shù)據(jù)盡量轉(zhuǎn)換成一組具有一定規(guī)則的數(shù)據(jù)濒生。
為什么MapReduce計算模型需要Shuffle過程?我們都知道MapReduce計算模型一般包括兩個重要的階段:Map是映射埋泵,負責數(shù)據(jù)的過濾分發(fā);Reduce是規(guī)約,負責數(shù)據(jù)的計算歸并罪治。Reduce的數(shù)據(jù)來源于Map秋泄,Map的輸出即是Reduce的輸入,Reduce需要通過Shuffle來獲取數(shù)據(jù)规阀。
從Map輸出到Reduce輸入的整個過程可以廣義地稱為Shuffle恒序。Shuffle橫跨Map端和Reduce端,在Map端包括Spill過程谁撼,在Reduce端包括copy和sort過程歧胁,如圖所示:
Spill過程
Spill過程包括輸出、排序厉碟、溢寫喊巍、合并等步驟,如圖所示:
Collect
每個Map任務(wù)不斷地以對的形式把數(shù)據(jù)輸出到在內(nèi)存中構(gòu)造的一個環(huán)形數(shù)據(jù)結(jié)構(gòu)中箍鼓。使用環(huán)形數(shù)據(jù)結(jié)構(gòu)是為了更有效地使用內(nèi)存空間崭参,在內(nèi)存中放置盡可能多的數(shù)據(jù)。
這個數(shù)據(jù)結(jié)構(gòu)其實就是個字節(jié)數(shù)組款咖,叫Kvbuffer何暮,名如其義,但是這里面不光放置了數(shù)據(jù)铐殃,還放置了一些索引數(shù)據(jù)海洼,給放置索引數(shù)據(jù)的區(qū)域起了一個Kvmeta的別名,在Kvbuffer的一塊區(qū)域上穿了一個IntBuffer(字節(jié)序采用的是平臺自身的字節(jié)序)的馬甲富腊。數(shù)據(jù)區(qū)域和索引數(shù)據(jù)區(qū)域在Kvbuffer中是相鄰不重疊的兩個區(qū)域坏逢,用一個分界點來劃分兩者,分界點不是亙古不變的,而是每次Spill之后都會更新一次是整。初始的分界點是0肖揣,數(shù)據(jù)的存儲方向是向上增長,索引數(shù)據(jù)的存儲方向是向下增長浮入,如圖所示:
Kvbuffer的存放指針bufindex是一直悶著頭地向上增長龙优,比如bufindex初始值為0,一個Int型的key寫完之后舵盈,bufindex增長為4,一個Int型的value寫完之后球化,bufindex增長為8秽晚。
索引是對在kvbuffer中的索引,是個四元組筒愚,包括:value的起始位置赴蝇、key的起始位置、partition值巢掺、value的長度句伶,占用四個Int長度,Kvmeta的存放指針Kvindex每次都是向下跳四個“格子”陆淀,然后再向上一個格子一個格子地填充四元組的數(shù)據(jù)考余。比如Kvindex初始位置是-4,當?shù)谝粋€寫完之后轧苫,(Kvindex+0)的位置存放value的起始位置楚堤、(Kvindex+1)的位置存放key的起始位置、(Kvindex+2)的位置存放partition的值含懊、(Kvindex+3)的位置存放value的長度身冬,然后Kvindex跳到-8位置,等第二個和索引寫完之后岔乔,Kvindex跳到-32位置酥筝。
Kvbuffer的大小雖然可以通過參數(shù)設(shè)置,但是總共就那么大雏门,和索引不斷地增加嘿歌,加著加著,Kvbuffer總有不夠用的那天茁影,那怎么辦?把數(shù)據(jù)從內(nèi)存刷到磁盤上再接著往內(nèi)存寫數(shù)據(jù)搅幅,把Kvbuffer中的數(shù)據(jù)刷到磁盤上的過程就叫Spill,多么明了的叫法呼胚,內(nèi)存中的數(shù)據(jù)滿了就自動地spill到具有更大空間的磁盤茄唐。
關(guān)于Spill觸發(fā)的條件,也就是Kvbuffer用到什么程度開始Spill,還是要講究一下的沪编。如果把Kvbuffer用得死死得呼盆,一點縫都不剩的時候再開始Spill,那Map任務(wù)就需要等Spill完成騰出空間之后才能繼續(xù)寫數(shù)據(jù);如果Kvbuffer只是滿到一定程度蚁廓,比如80%的時候就開始Spill访圃,那在Spill的同時,Map任務(wù)還能繼續(xù)寫數(shù)據(jù)相嵌,如果Spill夠快腿时,Map可能都不需要為空閑空間而發(fā)愁。兩利相衡取其大饭宾,一般選擇后者批糟。
Spill這個重要的過程是由Spill線程承擔,Spill線程從Map任務(wù)接到“命令”之后就開始正式干活看铆,干的活叫SortAndSpill徽鼎,原來不僅僅是Spill,在Spill之前還有個頗具爭議性的Sort弹惦。
Sort
先把Kvbuffer中的數(shù)據(jù)按照partition值和key兩個關(guān)鍵字升序排序否淤,移動的只是索引數(shù)據(jù),排序結(jié)果是Kvmeta中數(shù)據(jù)按照partition為單位聚集在一起棠隐,同一partition內(nèi)的按照key有序石抡。
在此我向大家推薦一個大數(shù)據(jù)開發(fā)交流圈:874267457? 里面整理了一大份學習資料,全都是些干貨助泽,包括大數(shù)據(jù)技術(shù)入門汁雷,大數(shù)據(jù)離線處理、數(shù)據(jù)實時處理报咳、Hadoop 侠讯、Spark、Flink暑刃、推薦系統(tǒng)算法以及源碼解析等厢漩,送給每一位大數(shù)據(jù)小伙伴,讓自學更輕松岩臣。這里不止是小白聚集地溜嗜,還有大牛在線解答!歡迎初學和進階中的小伙伴一起進群學習交流架谎,共同進步炸宵!
Spill
Spill線程為這次Spill過程創(chuàng)建一個磁盤文件:從所有的本地目錄中輪訓(xùn)查找能存儲這么大空間的目錄,找到之后在其中創(chuàng)建一個類似于“spill12.out”的文件谷扣。Spill線程根據(jù)排過序的Kvmeta挨個partition的把數(shù)據(jù)吐到這個文件中土全,一個partition對應(yīng)的數(shù)據(jù)吐完之后順序地吐下個partition捎琐,直到把所有的partition遍歷完。一個partition在文件中對應(yīng)的數(shù)據(jù)也叫段(segment)裹匙。
所有的partition對應(yīng)的數(shù)據(jù)都放在這個文件里瑞凑,雖然是順序存放的,但是怎么直接知道某個partition在這個文件中存放的起始位置呢?強大的索引又出場了概页。有一個三元組記錄某個partition對應(yīng)的數(shù)據(jù)在這個文件中的索引:起始位置籽御、原始數(shù)據(jù)長度、壓縮之后的數(shù)據(jù)長度惰匙,一個partition對應(yīng)一個三元組技掏。然后把這些索引信息存放在內(nèi)存中,如果內(nèi)存中放不下了项鬼,后續(xù)的索引信息就需要寫到磁盤文件中了:從所有的本地目錄中輪訓(xùn)查找能存儲這么大空間的目錄哑梳,找到之后在其中創(chuàng)建一個類似于“spill12.out.index”的文件,文件中不光存儲了索引數(shù)據(jù)秃臣,還存儲了crc32的校驗數(shù)據(jù)涧衙。(spill12.out.index不一定在磁盤上創(chuàng)建哪工,如果內(nèi)存(默認1M空間)中能放得下就放在內(nèi)存中奥此,即使在磁盤上創(chuàng)建了,和spill12.out文件也不一定在同一個目錄下雁比。)
每一次Spill過程就會最少生成一個out文件稚虎,有時還會生成index文件,Spill的次數(shù)也烙印在文件名中偎捎。索引文件和數(shù)據(jù)文件的對應(yīng)關(guān)系如下圖所示:
話分兩端蠢终,在Spill線程如火如荼的進行SortAndSpill工作的同時,Map任務(wù)不會因此而停歇茴她,而是一無既往地進行著數(shù)據(jù)輸出寻拂。Map還是把數(shù)據(jù)寫到kvbuffer中,那問題就來了:只顧著悶頭按照bufindex指針向上增長丈牢,kvmeta只顧著按照Kvindex向下增長祭钉,是保持指針起始位置不變繼續(xù)跑呢,還是另謀它路?如果保持指針起始位置不變己沛,很快bufindex和Kvindex就碰頭了慌核,碰頭之后再重新開始或者移動內(nèi)存都比較麻煩,不可取申尼。Map取kvbuffer中剩余空間的中間位置垮卓,用這個位置設(shè)置為新的分界點,bufindex指針移動到這個分界點师幕,Kvindex移動到這個分界點的-16位置粟按,然后兩者就可以和諧地按照自己既定的軌跡放置數(shù)據(jù)了,當Spill完成,空間騰出之后钾怔,不需要做任何改動繼續(xù)前進碱呼。分界點的轉(zhuǎn)換如下圖所示:
Map任務(wù)總要把輸出的數(shù)據(jù)寫到磁盤上,即使輸出數(shù)據(jù)量很小在內(nèi)存中全部能裝得下宗侦,在最后也會把數(shù)據(jù)刷到磁盤上愚臀。
Merge
Map任務(wù)如果輸出數(shù)據(jù)量很大,可能會進行好幾次Spill矾利,out文件和Index文件會產(chǎn)生很多姑裂,分布在不同的磁盤上。最后把這些文件進行合并的merge過程閃亮登場男旗。
Merge過程怎么知道產(chǎn)生的Spill文件都在哪了呢?從所有的本地目錄上掃描得到產(chǎn)生的Spill文件舶斧,然后把路徑存儲在一個數(shù)組里。Merge過程又怎么知道Spill的索引信息呢?沒錯察皇,也是從所有的本地目錄上掃描得到Index文件茴厉,然后把索引信息存儲在一個列表里。到這里什荣,又遇到了一個值得納悶的地方矾缓。
在之前Spill過程中的時候為什么不直接把這些信息存儲在內(nèi)存中呢,何必又多了這步掃描的操作?特別是Spill的索引數(shù)據(jù)稻爬,之前當內(nèi)存超限之后就把數(shù)據(jù)寫到磁盤嗜闻,現(xiàn)在又要從磁盤把這些數(shù)據(jù)讀出來,還是需要裝到更多的內(nèi)存中桅锄。之所以多此一舉琉雳,是因為這kvbuffer這個內(nèi)存大戶已經(jīng)不再使用可以回收,有內(nèi)存空間來裝這些數(shù)據(jù)了友瘤。(對于內(nèi)存空間較大的土豪來說翠肘,用內(nèi)存來省卻這兩個io步驟還是值得考慮的。)然后為merge過程創(chuàng)建一個叫file.out的文件和一個叫file.out.Index的文件用來存儲最終的輸出和索引辫秧。
一個partition一個partition的進行合并輸出束倍。對于某個partition來說,從索引列表中查詢這個partition對應(yīng)的所有索引信息茶没,每個對應(yīng)一個段插入到段列表中肌幽。也就是這個partition對應(yīng)一個段列表,記錄所有的Spill文件中對應(yīng)的這個partition那段數(shù)據(jù)的文件名抓半、起始位置喂急、長度等等。
然后對這個partition對應(yīng)的所有的segment進行合并笛求,目標是合并成一個segment廊移。當這個partition對應(yīng)很多個segment時糕簿,會分批地進行合并:先從segment列表中把第一批取出來,以key為關(guān)鍵字放置成最小堆狡孔,然后從最小堆中每次取出最小的輸出到一個臨時文件中懂诗,這樣就把這一批段合并成一個臨時的段,把它加回到segment列表中;再從segment列表中把第二批取出來合并輸出到一個臨時segment苗膝,把其加入到列表中;這樣往復(fù)執(zhí)行殃恒,直到剩下的段是一批,輸出到最終的文件中辱揭。最終的索引數(shù)據(jù)仍然輸出到Index文件中离唐。
Map端的Shuffle過程到此結(jié)束。
Copy
Reduce任務(wù)通過HTTP向各個Map任務(wù)拖取它所需要的數(shù)據(jù)问窃。每個節(jié)點都會啟動一個常駐的HTTP server亥鬓,其中一項服務(wù)就是響應(yīng)Reduce拖取Map數(shù)據(jù)。當有MapOutput的HTTP請求過來的時候域庇,HTTP server就讀取相應(yīng)的Map輸出文件中對應(yīng)這個Reduce部分的數(shù)據(jù)通過網(wǎng)絡(luò)流輸出給Reduce嵌戈。
Reduce任務(wù)拖取某個Map對應(yīng)的數(shù)據(jù),如果在內(nèi)存中能放得下這次數(shù)據(jù)的話就直接把數(shù)據(jù)寫到內(nèi)存中听皿。Reduce要向每個Map去拖取數(shù)據(jù)熟呛,在內(nèi)存中每個Map對應(yīng)一塊數(shù)據(jù),當內(nèi)存中存儲的Map數(shù)據(jù)占用空間達到一定程度的時候写穴,開始啟動內(nèi)存中merge惰拱,把內(nèi)存中的數(shù)據(jù)merge輸出到磁盤上一個文件中雌贱。
如果在內(nèi)存中不能放得下這個Map的數(shù)據(jù)的話啊送,直接把Map數(shù)據(jù)寫到磁盤上,在本地目錄創(chuàng)建一個文件欣孤,從HTTP流中讀取數(shù)據(jù)然后寫到磁盤馋没,使用的緩存區(qū)大小是64K。拖一個Map數(shù)據(jù)過來就會創(chuàng)建一個文件降传,當文件數(shù)量達到一定閾值時篷朵,開始啟動磁盤文件merge,把這些文件合并輸出到一個文件婆排。
有些Map的數(shù)據(jù)較小是可以放在內(nèi)存中的声旺,有些Map的數(shù)據(jù)較大需要放在磁盤上,這樣最后Reduce任務(wù)拖過來的數(shù)據(jù)有些放在內(nèi)存中了有些放在磁盤上段只,最后會對這些來一個全局合并腮猖。
Merge Sort
這里使用的Merge和Map端使用的Merge過程一樣。Map的輸出數(shù)據(jù)已經(jīng)是有序的赞枕,Merge進行一次合并排序澈缺,所謂Reduce端的sort過程就是這個合并的過程坪创。一般Reduce是一邊copy一邊sort,即copy和sort兩個階段是重疊而不是完全分開的姐赡。Reduce端的Shuffle過程至此結(jié)束莱预。
Spark的Shuffle過程介紹
Shuffle Writer
Spark豐富了任務(wù)類型,有些任務(wù)之間數(shù)據(jù)流轉(zhuǎn)不需要通過Shuffle项滑,但是有些任務(wù)之間還是需要通過Shuffle來傳遞數(shù)據(jù)依沮,比如widedependency的group by key。
Spark中需要Shuffle輸出的Map任務(wù)會為每個Reduce創(chuàng)建對應(yīng)的bucket枪狂,Map產(chǎn)生的結(jié)果會根據(jù)設(shè)置的partitioner得到對應(yīng)的bucketId悉抵,然后填充到相應(yīng)的bucket中去。每個Map的輸出結(jié)果可能包含所有的Reduce所需要的數(shù)據(jù)摘完,所以每個Map會創(chuàng)建R個bucket(R是reduce的個數(shù))姥饰,M個Map總共會創(chuàng)建M*R個bucket。
Map創(chuàng)建的bucket其實對應(yīng)磁盤上的一個文件孝治,Map的結(jié)果寫到每個bucket中其實就是寫到那個磁盤文件中列粪,這個文件也被稱為blockFile,是Disk Block Manager管理器通過文件名的Hash值對應(yīng)到本地目錄的子目錄中創(chuàng)建的谈飒。每個Map要在節(jié)點上創(chuàng)建R個磁盤文件用于結(jié)果輸出岂座,Map的結(jié)果是直接輸出到磁盤文件上的,100KB的內(nèi)存緩沖是用來創(chuàng)建Fast Buffered OutputStream輸出流杭措。這種方式一個問題就是Shuffle文件過多费什。
針對上述Shuffle過程產(chǎn)生的文件過多問題,Spark有另外一種改進的Shuffle過程:consolidation Shuffle,以期顯著減少Shuffle文件的數(shù)量享扔。在consolidation Shuffle中每個bucket并非對應(yīng)一個文件红且,而是對應(yīng)文件中的一個segment部分。
Job的map在某個節(jié)點上第一次執(zhí)行稿黍,為每個reduce創(chuàng)建bucket對應(yīng)的輸出文件,把這些文件組織成ShuffleFileGroup崩哩,當這次map執(zhí)行完之后巡球,這個ShuffleFileGroup可以釋放為下次循環(huán)利用;當又有map在這個節(jié)點上執(zhí)行時,不需要創(chuàng)建新的bucket文件邓嘹,而是在上次的ShuffleFileGroup中取得已經(jīng)創(chuàng)建的文件繼續(xù)追加寫一個segment;當前次map還沒執(zhí)行完酣栈,ShuffleFileGroup還沒有釋放,這時如果有新的map在這個節(jié)點上執(zhí)行汹押,無法循環(huán)利用這個ShuffleFileGroup矿筝,而是只能創(chuàng)建新的bucket文件組成新的ShuffleFileGroup來寫輸出。
比如一個Job有3個Map和2個reduce:(1)如果此時集群有3個節(jié)點有空槽鲸阻,每個節(jié)點空閑了一個core跋涣,則3個Map會調(diào)度到這3個節(jié)點上執(zhí)行缨睡,每個Map都會創(chuàng)建2個Shuffle文件,總共創(chuàng)建6個Shuffle文件;
(2)如果此時集群有2個節(jié)點有空槽陈辱,每個節(jié)點空閑了一個core奖年,則2個Map先調(diào)度到這2個節(jié)點上執(zhí)行,每個Map都會創(chuàng)建2個Shuffle文件沛贪,然后其中一個節(jié)點執(zhí)行完Map之后又調(diào)度執(zhí)行另一個Map陋守,則這個Map不會創(chuàng)建新的Shuffle文件,而是把結(jié)果輸出追加到之前Map創(chuàng)建的Shuffle文件中;總共創(chuàng)建4個Shuffle文件;
(3)如果此時集群有2個節(jié)點有空槽利赋,一個節(jié)點有2個空core一個節(jié)點有1個空core水评,則一個節(jié)點調(diào)度2個Map一個節(jié)點調(diào)度1個Map,調(diào)度2個Map的節(jié)點上媚送,一個Map創(chuàng)建了Shuffle文件中燥,后面的Map還是會創(chuàng)建新的Shuffle文件,因為上一個Map還正在寫塘偎,它創(chuàng)建的ShuffleFileGroup還沒有釋放;總共創(chuàng)建6個Shuffle文件疗涉。
Shuffle Fetcher
Reduce去拖Map的輸出數(shù)據(jù),Spark提供了兩套不同的拉取數(shù)據(jù)框架:通過socket連接去取數(shù)據(jù);使用netty框架去取數(shù)據(jù)吟秩。
每個節(jié)點的Executor會創(chuàng)建一個BlockManager咱扣,其中會創(chuàng)建一個BlockManagerWorker用于響應(yīng)請求。當Reduce的GET_BLOCK的請求過來時涵防,讀取本地文件將這個blockId的數(shù)據(jù)返回給Reduce闹伪。如果使用的是Netty框架,BlockManager會創(chuàng)建ShuffleSender用于發(fā)送Shuffle數(shù)據(jù)壮池。
并不是所有的數(shù)據(jù)都是通過網(wǎng)絡(luò)讀取偏瓤,對于在本節(jié)點的Map數(shù)據(jù),Reduce直接去磁盤上讀取而不再通過網(wǎng)絡(luò)框架火窒。
Reduce拖過來數(shù)據(jù)之后以什么方式存儲呢?Spark Map輸出的數(shù)據(jù)沒有經(jīng)過排序硼补,Spark Shuffle過來的數(shù)據(jù)也不會進行排序驮肉,Spark認為Shuffle過程中的排序不是必須的熏矿,并不是所有類型的Reduce需要的數(shù)據(jù)都需要排序,強制地進行排序只會增加Shuffle的負擔离钝。Reduce拖過來的數(shù)據(jù)會放在一個HashMap中票编,HashMap中存儲的也是對,key是Map輸出的key卵渴,Map輸出對應(yīng)這個key的所有value組成HashMap的value慧域。Spark將Shuffle取過來的每一個對插入或者更新到HashMap中,來一個處理一個浪读。HashMap全部放在內(nèi)存中昔榴。
Shuffle取過來的數(shù)據(jù)全部存放在內(nèi)存中辛藻,對于數(shù)據(jù)量比較小或者已經(jīng)在Map端做過合并處理的Shuffle數(shù)據(jù),占用內(nèi)存空間不會太大互订,但是對于比如group by key這樣的操作吱肌,Reduce需要得到key對應(yīng)的所有value,并將這些value組一個數(shù)組放在內(nèi)存中仰禽,這樣當數(shù)據(jù)量較大時氮墨,就需要較多內(nèi)存。
當內(nèi)存不夠時吐葵,要不就失敗规揪,要不就用老辦法把內(nèi)存中的數(shù)據(jù)移到磁盤上放著。Spark意識到在處理數(shù)據(jù)規(guī)模遠遠大于內(nèi)存空間時所帶來的不足温峭,引入了一個具有外部排序的方案猛铅。Shuffle過來的數(shù)據(jù)先放在內(nèi)存中,當內(nèi)存中存儲的對超過1000并且內(nèi)存使用超過70%時凤藏,判斷節(jié)點上可用內(nèi)存如果還足夠奕坟,則把內(nèi)存緩沖區(qū)大小翻倍,如果可用內(nèi)存不再夠了清笨,則把內(nèi)存中的對排序然后寫到磁盤文件中月杉。最后把內(nèi)存緩沖區(qū)中的數(shù)據(jù)排序之后和那些磁盤文件組成一個最小堆,每次從最小堆中讀取最小的數(shù)據(jù)抠艾,這個和MapReduce中的merge過程類似苛萎。
MapReduce和Spark的Shuffle過程對比
Shuffle后續(xù)優(yōu)化方向
通過上面的介紹,我們了解到检号,Shuffle過程的主要存儲介質(zhì)是磁盤腌歉,盡量的減少IO是Shuffle的主要優(yōu)化方向。我們腦海中都有那個經(jīng)典的存儲金字塔體系齐苛,Shuffle過程為什么把結(jié)果都放在磁盤上翘盖,那是因為現(xiàn)在內(nèi)存再大也大不過磁盤,內(nèi)存就那么大凹蜂,還這么多張嘴吃馍驯,當然是分配給最需要的了。如果具有“土豪”內(nèi)存節(jié)點玛痊,減少Shuffle
IO的最有效方式無疑是盡量把數(shù)據(jù)放在內(nèi)存中汰瘫。下面列舉一些現(xiàn)在看可以優(yōu)化的方面,期待經(jīng)過我們不斷的努力擂煞,TDW計算引擎運行地更好混弥。
MapReduce Shuffle后續(xù)優(yōu)化方向
壓縮:對數(shù)據(jù)進行壓縮,減少寫讀數(shù)據(jù)量;減少不必要的排序:并不是所有類型的Reduce需要的數(shù)據(jù)都是需要排序的对省,排序這個nb的過程如果不需要最好還是不要的好;
內(nèi)存化:Shuffle的數(shù)據(jù)不放在磁盤而是盡量放在內(nèi)存中蝗拿,除非逼不得已往磁盤上放;當然了如果有性能和內(nèi)存相當?shù)牡谌酱鎯ο到y(tǒng)晾捏,那放在第三方存儲系統(tǒng)上也是很好的;這個是個大招;網(wǎng)絡(luò)框架:netty的性能據(jù)說要占優(yōu)了;本節(jié)點上的數(shù)據(jù)不走網(wǎng)絡(luò)框架:對于本節(jié)點上的Map輸出,Reduce直接去讀吧哀托,不需要繞道網(wǎng)絡(luò)框架粟瞬。
Spark Shuffle后續(xù)優(yōu)化方向
Spark作為MapReduce的進階架構(gòu),對于Shuffle過程已經(jīng)是優(yōu)化了的萤捆,特別是對于那些具有爭議的步驟已經(jīng)做了優(yōu)化裙品,但是Spark的Shuffle對于我們來說在一些方面還是需要優(yōu)化的。
壓縮:對數(shù)據(jù)進行壓縮俗或,減少寫讀數(shù)據(jù)量;內(nèi)存化:Spark歷史版本中是有這樣設(shè)計的:Map寫數(shù)據(jù)先把數(shù)據(jù)全部寫到內(nèi)存中市怎,寫完之后再把數(shù)據(jù)刷到磁盤上;考慮內(nèi)存是緊缺資源,后來修改成把數(shù)據(jù)直接寫到磁盤了;對于具有較大內(nèi)存的集群來講辛慰,還是盡量地往內(nèi)存上寫吧区匠,內(nèi)存放不下了再放磁盤。
感謝您的觀看帅腌,如有不足之處驰弄,歡迎批評指正。最后祝福所有遇到瓶頸的大數(shù)據(jù)程序員們突破自己速客,祝福大家在往后的工作與面試中一切順利戚篙。