1 Map side tuning參數(shù)
1.1 MapTask運行內(nèi)部原理

當(dāng)map task開始運算,并產(chǎn)生中間數(shù)據(jù)時,其產(chǎn)生的中間結(jié)果并非直接就簡單的寫入磁盤。這中間的過程比較復(fù)雜,并且利用到了內(nèi)存buffer來進(jìn)行已經(jīng)產(chǎn)生的部分結(jié)果的緩存,并在內(nèi)存buffer中進(jìn)行一些預(yù)排序來優(yōu)化整個map的性能。如上圖所示,每一個map都會對應(yīng)存在一個內(nèi)存buffer(MapOutputBuffer,即上圖的buffer in memory),map會將已經(jīng)產(chǎn)生的部分結(jié)果先寫入到該buffer中,這個buffer默認(rèn)是100MB大小,但是這個大小是可以根據(jù)job提交時的參數(shù)設(shè)定來調(diào)整的,該參數(shù)即為:
io.sort.mb。當(dāng)map的產(chǎn)生數(shù)據(jù)非常大時,并且把io.sort.mb調(diào)大,那么map在整個計算過程中spill的次數(shù)就勢必會降低,map task對磁盤的操作就會變少,如果map tasks的瓶頸在磁盤上,這樣調(diào)整就會大大提高map的計算性能。map做sort和spill的內(nèi)存結(jié)構(gòu)如下如所示:

map在運行過程中,不停的向該buffer中寫入已有的計算結(jié)果,但是該buffer并不一定能將全部的map輸出緩存下來,當(dāng)map輸出超出一定閾值(比如100M),那么map就必須將該buffer中的數(shù)據(jù)寫入到磁盤中去,這個過程在mapreduce中叫做spill。map并不是要等到將該buffer全部寫滿時才進(jìn)行spill,因為如果全部寫滿了再去寫spill,勢必會造成map的計算部分等待buffer釋放空間的情況。所以,map其實是當(dāng)buffer被寫滿到一定程度(比如80%)時,就開始進(jìn)行spill。這個閾值也是由一個job的配置參數(shù)來控制,即io.sort.spill.percent,默認(rèn)為0.80或80%。這個參數(shù)同樣也是影響spill頻繁程度,進(jìn)而影響map task運行周期對磁盤的讀寫頻率的。但非特殊情況下,通常不需要人為的調(diào)整。調(diào)整io.sort.mb對用戶來說更加方便。
當(dāng)map task的計算部分全部完成后,如果map有輸出,就會生成一個或者多個spill文件,這些文件就是map的輸出結(jié)果。map在正常退出之前,需要將這些spill合并(merge)成一個,所以map在結(jié)束之前還有一個merge的過程。merge的過程中,有一個參數(shù)可以調(diào)整這個過程的行為,該參數(shù)為:io.sort.factor。該參數(shù)默認(rèn)為10。它表示當(dāng)merge spill文件時,最多能有多少并行的stream向merge文件中寫入。比如如果map產(chǎn)生的數(shù)據(jù)非常的大,產(chǎn)生的spill文件大于10,而io.sort.factor使用的是默認(rèn)的10,那么當(dāng)map計算完成做merge時,就沒有辦法一次將所有的spill文件merge成一個,而是會分多次,每次最多10個stream。這也就是說,當(dāng)map的中間結(jié)果非常大,調(diào)大io.sort.factor,有利于減少merge次數(shù),進(jìn)而減少map對磁盤的讀寫頻率,有可能達(dá)到優(yōu)化作業(yè)的目的。
當(dāng)job指定了combiner的時候,我們都知道m(xù)ap介紹后會在map端根據(jù)combiner定義的函數(shù)將map結(jié)果進(jìn)行合并。運行combiner函數(shù)的時機(jī)有可能會是merge完成之前,或者之后,這個時機(jī)可以由一個參數(shù)控制,即min.num.spill.for.combine(default 3),當(dāng)job中設(shè)定了combiner,并且spill數(shù)最少有3個的時候,那么combiner函數(shù)就會在merge產(chǎn)生結(jié)果文件之前運行。通過這樣的方式,就可以在spill非常多需要merge,并且很多數(shù)據(jù)需要做conbine的時候,減少寫入到磁盤文件的數(shù)據(jù)數(shù)量,同樣是為了減少對磁盤的讀寫頻率,有可能達(dá)到優(yōu)化作業(yè)的目的。
減少中間結(jié)果讀寫進(jìn)出磁盤的方法不止這些,還有就是壓縮。也就是說map的中間,無論是spill的時候,還是最后merge產(chǎn)生的結(jié)果文件,都是可以壓縮的。壓縮的好處在于,通過壓縮減少寫入讀出磁盤的數(shù)據(jù)量。對中間結(jié)果非常大,磁盤速度成為map執(zhí)行瓶頸的job,尤其有用??刂苖ap中間結(jié)果是否使用壓縮的參數(shù)為:mapred.compress.map.output(true/false)。將這個參數(shù)設(shè)置為true時,那么map在寫中間結(jié)果時,就會將數(shù)據(jù)壓縮后再寫入磁盤,讀結(jié)果時也會采用先解壓后讀取數(shù)據(jù)。這樣做的后果就是:寫入磁盤的中間結(jié)果數(shù)據(jù)量會變少,但是cpu會消耗一些用來壓縮和解壓。所以這種方式通常適合job中間結(jié)果非常大,瓶頸不在cpu,而是在磁盤的讀寫的情況。說的直白一些就是用cpu換IO。根據(jù)觀察,通常大部分的作業(yè)cpu都不是瓶頸,除非運算邏輯異常復(fù)雜。所以對中間結(jié)果采用壓縮通常來說是有收益的。以下是一個wordcount中間結(jié)果采用壓縮和不采用壓縮產(chǎn)生的map中間結(jié)果本地磁盤讀寫的數(shù)據(jù)量對比:
更多詳細(xì)信息,請您微信關(guān)注“計算網(wǎng)”公眾號: