如何在開發(fā)ETL過程中毅厚,設(shè)置參數(shù)垮刹,或者不設(shè)置參數(shù),跟依賴的mapreduce平臺(tái)之間是什么關(guān)系?
dfs.block.size
? 決定HDFS文件block數(shù)量的多少(文件個(gè)數(shù)),它會(huì)間接的影響Job Tracker的調(diào)度和內(nèi)存的占用(更影響內(nèi)存的使用),
mapred.map.tasks.speculative.execution=true
mapred.reduce.tasks.speculative.execution=true
這是兩個(gè)推測式執(zhí)行的配置項(xiàng),默認(rèn)是true
所謂的推測執(zhí)行朴译,就是當(dāng)所有task都開始運(yùn)行之后,Job Tracker會(huì)統(tǒng)計(jì)所有任務(wù)的平均進(jìn)度逝变,如果某個(gè)task所在的task node機(jī)器配
置比較低或者CPU load很高(原因很多)增淹,導(dǎo)致任務(wù)執(zhí)行比總體任務(wù)的平均執(zhí)行要慢,此時(shí)Job Tracker會(huì)啟動(dòng)一個(gè)新的任務(wù)
(duplicate task)漓拾,原有任務(wù)和新任務(wù)哪個(gè)先執(zhí)行完就把另外一個(gè)kill掉阁最,這也是我們經(jīng)常在Job Tracker頁面看到任務(wù)執(zhí)行成功,但
是總有些任務(wù)被kill骇两,就是這個(gè)原因速种。
mapred.child.java.opts
一般來說,都是reduce耗費(fèi)內(nèi)存比較大低千,這個(gè)選項(xiàng)是用來設(shè)置JVM堆的最大可用內(nèi)存配阵,但不要設(shè)置過大,如果超過2G(這是數(shù)字有
待考證)示血,就應(yīng)該考慮一下優(yōu)化程序棋傍。
Input Split的大小,決定了一個(gè)Job擁有多少個(gè)map难审,默認(rèn)64M每個(gè)Split瘫拣,如果輸入的數(shù)據(jù)量巨大,那么默認(rèn)的64M的block會(huì)有特
別多Map Task告喊,集群的網(wǎng)絡(luò)傳輸會(huì)很大麸拄,給Job Tracker的調(diào)度、隊(duì)列黔姜、內(nèi)存都會(huì)帶來很大壓力拢切。
mapred.min.split.size
這個(gè)配置決定了每個(gè)Input Split 的最小值,也間接決定了一個(gè)job的map數(shù)量
HDFS塊大小是在job寫入時(shí)決定的,而分片的大小,是由三個(gè)元素決定的(在3各種去最大的那個(gè))
(1) 輸入的塊數(shù) (2) Mapred.min.split.size (3) Job.setNumMapTasks()
mapred.compress.map.output
壓縮Map的輸出,這樣做有兩個(gè)好處:
a)壓縮是在內(nèi)存中進(jìn)行地淀,所以寫入map本地磁盤的數(shù)據(jù)就會(huì)變小失球,大大減少了本地IO次數(shù)
b) Reduce從每個(gè)map節(jié)點(diǎn)copy數(shù)據(jù),也會(huì)明顯降低網(wǎng)絡(luò)傳輸?shù)臅r(shí)間
注:數(shù)據(jù)序列化其實(shí)效果會(huì)更好帮毁,無論是磁盤IO還是數(shù)據(jù)大小实苞,都會(huì)明顯的降低。
io.sort.mb
以MB為單位烈疚,默認(rèn)100M黔牵,這個(gè)值比較小
map節(jié)點(diǎn)沒運(yùn)行完時(shí),內(nèi)存的數(shù)據(jù)過多爷肝,要將內(nèi)存中的內(nèi)容寫入洗盤猾浦,這個(gè)設(shè)置就是設(shè)置內(nèi)存緩沖的大小陆错,在suffle之前
這個(gè)選項(xiàng)定義了map輸出結(jié)果在內(nèi)存里占用buffer的大小,當(dāng)buffer達(dá)到某個(gè)閾值(后面那條配置)金赦,會(huì)啟動(dòng)一個(gè)后臺(tái)線程來對(duì)buffer
的內(nèi)容進(jìn)行排序音瓷,然后寫入本地磁盤(一個(gè)spill文件)
根據(jù)map輸出數(shù)據(jù)量的大小,可以適當(dāng)?shù)恼{(diào)整buffer的大小夹抗,注意是適當(dāng)?shù)恼{(diào)整绳慎,并不是越大越好,假設(shè)內(nèi)存無限大漠烧,
io.sort.mb=1024(1G), 和io.sort.mb=300 (300M)杏愤,前者未必比后者快:
(1)1G的數(shù)據(jù)排序一次
(2)排序3次,每次300MB
一定是后者快(歸并排序)
io.sort.spill.percent
這個(gè)值就是上面提到的buffer的閾值已脓,默認(rèn)是0.8珊楼,既80%,當(dāng)buffer中的數(shù)據(jù)達(dá)到這個(gè)閾值度液,后臺(tái)線程會(huì)起來對(duì)buffer中已有的數(shù)
據(jù)進(jìn)行排序厕宗,然后寫入磁盤,此時(shí)map輸出的數(shù)據(jù)繼續(xù)往剩余的20% buffer寫數(shù)據(jù)恨诱,如果buffer的剩余20%寫滿媳瞪,排序還沒結(jié)束,
map task被block等待照宝。
如果你確認(rèn)map輸出的數(shù)據(jù)基本有序,排序時(shí)間很短句葵,可以將這個(gè)閾值適當(dāng)調(diào)高厕鹃,更理想的,如果你的map輸出是有序的數(shù)據(jù)乍丈,那
么可以把buffer設(shè)的更大剂碴,閾值設(shè)置為1.
Io.sort.factor
同時(shí)打開的文件句柄的數(shù)量,默認(rèn)是10
當(dāng)一個(gè)map task執(zhí)行完之后轻专,本地磁盤上(mapred.local.dir)有若干個(gè)spill文件忆矛,map task最后做的一件事就是執(zhí)行merge sort,
把這些spill文件合成一個(gè)文件(partition请垛,combine階段)催训。
執(zhí)行merge sort的時(shí)候,每次同時(shí)打開多少個(gè)spill文件宗收,就是由io.sort.factor決定的漫拭。打開的文件越多,不一定merge sort就越
快混稽,也要根據(jù)數(shù)據(jù)情況適當(dāng)?shù)恼{(diào)整采驻。
注:merge排序的結(jié)果是兩個(gè)文件审胚,一個(gè)是index,另一個(gè)是數(shù)據(jù)文件礼旅,index文件記錄了每個(gè)不同的key在數(shù)據(jù)文件中的偏移量(即partition)膳叨。
在map節(jié)點(diǎn)上,如果發(fā)現(xiàn)map所在的子節(jié)點(diǎn)的機(jī)器io比較重痘系,原因可能是io.sort.factor這個(gè)設(shè)置的比較小懒鉴,io.sort.factor設(shè)置小的
話,如果spill文件比較多碎浇,merge成一個(gè)文件要很多輪讀取操作临谱,這樣就提升了io的負(fù)載。io.sort.mb小了奴璃,也會(huì)增加io的負(fù)載悉默。
如果設(shè)置了執(zhí)行combine的話,combine只是在merge的時(shí)候苟穆,增加了一步操作抄课,不會(huì)改變merge的流程,所以combine不會(huì)減少
或者增加文件個(gè)數(shù)雳旅。另外有個(gè)min.num.spills.for.combine的參數(shù)跟磨,表示執(zhí)行一個(gè)merge操作時(shí),如果輸入文件數(shù)小于這個(gè)數(shù)字攒盈,就
不調(diào)用combiner抵拘。如果設(shè)置了combiner,在寫spill文件的時(shí)候也會(huì)調(diào)用型豁,這樣加上merge時(shí)候的調(diào)用僵蛛,就會(huì)執(zhí)行兩次combine。
提高Reduce的執(zhí)行效率迎变,除了在Hadoop框架方面的優(yōu)化充尉,重點(diǎn)還是在代碼邏輯上的優(yōu)化.比如:對(duì)Reduce接受到的value可能有重
復(fù)的,此時(shí)如果用Java的Set或者STL的Set來達(dá)到去重的目的衣形,那么這個(gè)程序不是擴(kuò)展良好的(non-scalable)驼侠,受到數(shù)據(jù)量的限制,
當(dāng)數(shù)據(jù)膨脹谆吴,內(nèi)存勢必會(huì)溢出
mapred.reduce.parallel.copies
Reduce copy數(shù)據(jù)的線程數(shù)量倒源,默認(rèn)值是5
Reduce到每個(gè)完成的Map Task 拷貝數(shù)據(jù)(通過RPC調(diào)用),默認(rèn)同時(shí)啟動(dòng)5個(gè)線程到map節(jié)點(diǎn)取數(shù)據(jù)纪铺。這個(gè)配置還是很關(guān)鍵的相速,
如果你的map輸出數(shù)據(jù)很大,有時(shí)候會(huì)發(fā)現(xiàn)map早就100%了鲜锚,reduce卻在緩慢的變化突诬,那就是copy數(shù)據(jù)太慢了苫拍,比如5個(gè)線程
copy 10G的數(shù)據(jù),確實(shí)會(huì)很慢旺隙,這時(shí)就要調(diào)整這個(gè)參數(shù)绒极,但是調(diào)整的太大,容易造成集群擁堵蔬捷,所以 Job tuning的同時(shí)垄提,也是個(gè)權(quán)
衡的過程,要熟悉所用的數(shù)據(jù)周拐!
mapred.job.shuffle.input.buffer.percent
當(dāng)指定了JVM的堆內(nèi)存最大值以后铡俐,上面這個(gè)配置項(xiàng)就是Reduce用來存放從Map節(jié)點(diǎn)取過來的數(shù)據(jù)所用的內(nèi)存占堆內(nèi)存的比例,默
認(rèn)是0.7妥粟,既70%审丘,通常這個(gè)比例是夠了,但是對(duì)于大數(shù)據(jù)的情況勾给,這個(gè)比例還是小了一些滩报,0.8-0.9之間比較合適。(前提是你的
reduce函數(shù)不會(huì)瘋狂的吃掉內(nèi)存)
mapred.job.shuffle.merge.percent(默認(rèn)值0.66)
mapred.inmem.merge.threshold(默認(rèn)值1000)
第一個(gè)指的是從Map節(jié)點(diǎn)取數(shù)據(jù)過來播急,放到內(nèi)存脓钾,當(dāng)達(dá)到這個(gè)閾值之后,后臺(tái)啟動(dòng)線程(通常是Linux native process)把內(nèi)存中的
數(shù)據(jù)merge sort桩警,寫到reduce節(jié)點(diǎn)的本地磁盤可训;
第二個(gè)指的是從map節(jié)點(diǎn)取過來的文件個(gè)數(shù),當(dāng)達(dá)到這個(gè)個(gè)數(shù)之后生真,也進(jìn)行merger sort沉噩,然后寫到reduce節(jié)點(diǎn)的本地磁盤;這兩
個(gè)配置項(xiàng)第一個(gè)優(yōu)先判斷柱蟀,其次才判斷第二個(gè)thresh-hold。
從實(shí)際經(jīng)驗(yàn)來看蚜厉,mapred.job.shuffle.merge.percent默認(rèn)值偏小长已,完全可以設(shè)置到0.8左右;第二個(gè)默認(rèn)值1000昼牛,完全取決于
map輸出數(shù)據(jù)的大小术瓮,如果map輸出的數(shù)據(jù)很大,默認(rèn)值1000反倒不好贰健,應(yīng)該小一些胞四,如果map輸出的數(shù)據(jù)不大(light
weight),可以設(shè)置2000或者以上伶椿。
mapred.reduce.slowstart.completed.maps(map完成多少百分比時(shí)辜伟,開始shuffle)
當(dāng)map運(yùn)行慢氓侧,reduce運(yùn)行很快時(shí),如果不設(shè)置mapred.reduce.slowstart.completed.maps會(huì)使job的shuffle時(shí)間變的很長导狡,
map運(yùn)行完很早就開始了reduce约巷,導(dǎo)致reduce的slot一直處于被占用狀態(tài)。mapred.reduce.slowstart.completed.maps 這個(gè)值是
和“運(yùn)行完的map數(shù)除以總map數(shù)”做判斷的旱捧,當(dāng)后者大于等于設(shè)定的值時(shí)独郎,開始reduce的shuffle。所以當(dāng)map比reduce的執(zhí)行
時(shí)間多很多時(shí)枚赡,可以調(diào)整這個(gè)值(0.75,0.80,0.85及以上)
下面從流程里描述一下各個(gè)參數(shù)的作用:
當(dāng)map task開始運(yùn)算氓癌,并產(chǎn)生中間數(shù)據(jù)時(shí),其產(chǎn)生的中間結(jié)果并非直接就簡單的寫入磁盤贫橙。這中間的過程比較復(fù)雜贪婉,并且利用到了
內(nèi)存buffer來進(jìn)行已經(jīng)產(chǎn)生的部分結(jié)果的緩存,并在內(nèi)存buffer中進(jìn)行一些預(yù)排序來優(yōu)化整個(gè)map的性能料皇。每一個(gè)map都會(huì)對(duì)應(yīng)存
在一個(gè)內(nèi)存buffer(MapOutputBuffer)谓松,map會(huì)將已經(jīng)產(chǎn)生的部分結(jié)果先寫入到該buffer中,這個(gè)buffer默認(rèn)是100MB大小践剂,但
是這個(gè)大小是可以根據(jù)job提交時(shí)的參數(shù)設(shè)定來調(diào)整的鬼譬,該參數(shù)即為:io.sort.mb。當(dāng)map的產(chǎn)生數(shù)據(jù)非常大時(shí)逊脯,并且把io.sort.mb
調(diào)大优质,那么map在整個(gè)計(jì)算過程中spill的次數(shù)就勢必會(huì)降低,map task對(duì)磁盤的操作就會(huì)變少军洼,如果map tasks的瓶頸在磁盤上巩螃,
這樣調(diào)整就會(huì)大大提高map的計(jì)算性能。
map在運(yùn)行過程中匕争,不停的向該buffer中寫入已有的計(jì)算結(jié)果避乏,但是該buffer并不一定能將全部的map輸出緩存下來,當(dāng)map輸出
超出一定閾值(比如100M)甘桑,那么map就必須將該buffer中的數(shù)據(jù)寫入到磁盤中去拍皮,這個(gè)過程在mapreduce中叫做spill。map并
不是要等到將該buffer全部寫滿時(shí)才進(jìn)行spill跑杭,因?yàn)槿绻繉憹M了再去寫spill铆帽,勢必會(huì)造成map的計(jì)算部分等待buffer釋放空間的
情況。所以德谅,map其實(shí)是當(dāng)buffer被寫滿到一定程度(比如80%)時(shí)爹橱,就開始進(jìn)行spill。這個(gè)閾值也是由一個(gè)job的配置參數(shù)來控
制窄做,即io.sort.spill.percent愧驱,默認(rèn)為0.80或80%慰技。這個(gè)參數(shù)同樣也是影響spill頻繁程度,進(jìn)而影響map task運(yùn)行周期對(duì)磁盤的讀寫
頻率的冯键。但非特殊情況下惹盼,通常不需要人為的調(diào)整。調(diào)整io.sort.mb對(duì)用戶來說更加方便惫确。
當(dāng)map task的計(jì)算部分全部完成后手报,如果map有輸出,就會(huì)生成一個(gè)或者多個(gè)spill文件改化,這些文件就是map的輸出結(jié)果掩蛤。map在正
常退出之前,需要將這些spill合并(merge)成一個(gè)陈肛,所以map在結(jié)束之前還有一個(gè)merge的過程揍鸟。merge的過程中,有一個(gè)參數(shù)
可以調(diào)整這個(gè)過程的行為句旱,該參數(shù)為:io.sort.factor阳藻。該參數(shù)默認(rèn)為10。它表示當(dāng)merge spill文件時(shí)谈撒,最多能有多少并行的stream
向merge文件中寫入腥泥。比如如果map產(chǎn)生的數(shù)據(jù)非常的大,產(chǎn)生的spill文件大于10啃匿,而io.sort.factor使用的是默認(rèn)的10蛔外,那么當(dāng)
map計(jì)算完成做merge時(shí),就沒有辦法一次將所有的spill文件merge成一個(gè)溯乒,而是會(huì)分多次夹厌,每次最多10個(gè)stream。這也就是說裆悄,
當(dāng)map的中間結(jié)果非常大矛纹,調(diào)大io.sort.factor,有利于減少merge次數(shù)光稼,進(jìn)而減少map對(duì)磁盤的讀寫頻率崖技,有可能達(dá)到優(yōu)化作業(yè)的
目的。
當(dāng)job指定了combiner的時(shí)候钟哥,我們都知道m(xù)ap介紹后會(huì)在map端根據(jù)combiner定義的函數(shù)將map結(jié)果進(jìn)行合并。運(yùn)行combiner
函數(shù)的時(shí)機(jī)有可能會(huì)是merge完成之前瞎访,或者之后腻贰,這個(gè)時(shí)機(jī)可以由一個(gè)參數(shù)控制,即min.num.spill.for.combine(default 3)扒秸,
當(dāng)job中設(shè)定了combiner播演,并且spill數(shù)最少有3個(gè)的時(shí)候冀瓦,那么combiner函數(shù)就會(huì)在merge產(chǎn)生結(jié)果文件之前運(yùn)行。通過這樣的方
式写烤,就可以在spill非常多需要merge翼闽,并且很多數(shù)據(jù)需要做conbine的時(shí)候,減少寫入到磁盤文件的數(shù)據(jù)數(shù)量洲炊,同樣是為了減少對(duì)磁
盤的讀寫頻率感局,有可能達(dá)到優(yōu)化作業(yè)的目的。
減少中間結(jié)果讀寫進(jìn)出磁盤的方法不止這些暂衡,還有就是壓縮询微。也就是說map的中間,無論是spill的時(shí)候狂巢,還是最后merge產(chǎn)生的結(jié)
果文件撑毛,都是可以壓縮的。壓縮的好處在于唧领,通過壓縮減少寫入讀出磁盤的數(shù)據(jù)量藻雌。對(duì)中間結(jié)果非常大,磁盤速度成為map執(zhí)行瓶
頸的job斩个,尤其有用胯杭。控制map中間結(jié)果是否使用壓縮的參數(shù)為:mapred.compress.map.output(true/false)萨驶。將這個(gè)參數(shù)設(shè)置為
true時(shí)歉摧,那么map在寫中間結(jié)果時(shí),就會(huì)將數(shù)據(jù)壓縮后再寫入磁盤腔呜,讀結(jié)果時(shí)也會(huì)采用先解壓后讀取數(shù)據(jù)叁温。這樣做的后果就是:寫
入磁盤的中間結(jié)果數(shù)據(jù)量會(huì)變少,但是cpu會(huì)消耗一些用來壓縮和解壓核畴。所以這種方式通常適合job中間結(jié)果非常大膝但,瓶頸不在
cpu,而是在磁盤的讀寫的情況谤草。說的直白一些就是用cpu換IO跟束。根據(jù)觀察,通常大部分的作業(yè)cpu都不是瓶頸丑孩,除非運(yùn)算邏輯異常
復(fù)雜冀宴。所以對(duì)中間結(jié)果采用壓縮通常來說是有收益的。
當(dāng)采用map中間結(jié)果壓縮的情況下温学,用戶還可以選擇壓縮時(shí)采用哪種壓縮格式進(jìn)行壓縮略贮,現(xiàn)在hadoop支持的壓縮格式有:
GzipCodec,LzoCodec,BZip2Codec逃延,LzmaCodec等壓縮格式览妖。通常來說,想要達(dá)到比較平衡的cpu和磁盤壓縮比揽祥,LzoCodec
比較適合讽膏。但也要取決于job的具體情況。用戶若想要自行選擇中間結(jié)果的壓縮算法拄丰,可以設(shè)置配置參數(shù):
mapred.map.output.compression.codec=org.apache.hadoop.io.compress.DefaultCodec或者其他用戶自行選擇的壓縮方式府树。