Apache Hadoop最佳實(shí)踐和反模式解析
Apache Hadoop是一個(gè)用來(lái)構(gòu)建大規(guī)模共享存儲(chǔ)和計(jì)算設(shè)施的軟件。Hadoop集群已經(jīng)應(yīng)用在多種研究和開(kāi)發(fā)項(xiàng)目中,并且,Yahoo!, EBay, Facebook, LinkedIn, Twitter等公司,越來(lái)越多的的把它應(yīng)用在生產(chǎn)環(huán)境中。 這些已有的經(jīng)驗(yàn)是技術(shù)和投入的結(jié)晶,在許多情況下至關(guān)重要。因此,適當(dāng)?shù)氖褂肏adoop集群可以保證我們的投入能夠獲得最佳回報(bào)。
這篇博文簡(jiǎn)單總結(jié)了一些Hadoop應(yīng)用的最佳實(shí)踐。實(shí)際上,類(lèi)似于設(shè)計(jì)模式,我們引進(jìn)一個(gè)網(wǎng)格模式的的概念,來(lái)提供一個(gè)通用且可復(fù)用的針對(duì)運(yùn)行在網(wǎng)格上的應(yīng)用的解決方案。
這篇博文列舉了表現(xiàn)良好的應(yīng)用的特點(diǎn)并且提供了正確使用Hadoop框架的各種特性和功能的指導(dǎo)。這些特點(diǎn)很大程度上這由其本身特點(diǎn)而定,閱讀這篇文檔的一個(gè)好方法是從本質(zhì)上理解應(yīng)用,這些最佳實(shí)踐在Hadoop的多租戶(hù)環(huán)境下卓有成效,而且不會(huì)與框架本身的大多數(shù)原則和限制產(chǎn)生矛盾。
博文還強(qiáng)調(diào)了一些Hadoop應(yīng)用的反模式。
概述
Hadoop上的數(shù)據(jù)處理應(yīng)用一般使用Map-Reduce模型。
一個(gè)Map-Reduce作業(yè)通常會(huì)把輸入的數(shù)據(jù)集拆分成許多獨(dú)立的數(shù)據(jù)段,按照完全并行的方式一個(gè)map任務(wù)處理一段。框架把map的輸出排序,然后作為reduce的輸入。通常輸入和輸出都儲(chǔ)存在文件系統(tǒng)??蚣茇?fù)責(zé)調(diào)度、監(jiān)控任務(wù)的執(zhí)行以及重啟失敗的任務(wù)。
Map-Reduce應(yīng)用可以指定輸入輸出的位置,并提供了map與reduce功能的實(shí)現(xiàn),體現(xiàn)在Hadoop中是Mapper 和Reducer.這些只是作業(yè)配置的一部分參數(shù)。Hadoop客戶(hù)端提交作業(yè)(jar或者其他可執(zhí)行的程序)和配置給JobTracker,而JobTracker負(fù)責(zé)把程序和配置分發(fā)到各個(gè)slave,調(diào)度和監(jiān)控任務(wù)的執(zhí)行,并返回狀態(tài)信息給客戶(hù)端。
Map/Reduce框架的處理是基于<key, value>這樣的鍵值對(duì),也就是說(shuō),框架吧輸入數(shù)據(jù)視作一系列<key, value>鍵值對(duì)集合,然后產(chǎn)出另一些鍵值對(duì)作為輸出。
這是 Map-Reduce應(yīng)用的典型數(shù)據(jù)流
絕大多數(shù)在網(wǎng)格上運(yùn)行的Map-Reduce應(yīng)用都不會(huì)直接實(shí)現(xiàn)較低層次的Map-Reduce接口,而是借助于較高抽象層次的語(yǔ)言,例如Pig。
Oozie 是一個(gè)非常好的網(wǎng)格上的工作流管理和調(diào)度方案。Oozie 支持多種應(yīng)用接口 (Hadoop Map-Reduce, Pig, Hadoop Streaming, Hadoop Pipes, 等等.) 并且支持基于時(shí)間或數(shù)據(jù)可用性的調(diào)度。#p#
網(wǎng)格模式
這一部分是關(guān)于網(wǎng)格上運(yùn)行的Map-Reduce應(yīng)用的最佳實(shí)踐
輸入
Hadoop Map-Reduce 為處理海量數(shù)據(jù)而設(shè)計(jì)。maps過(guò)程以一種高度并行的方式來(lái)處理數(shù)據(jù), 通常一個(gè)map至少處理一個(gè)HDFS block,一般是128M。
- 默認(rèn)情況下,每個(gè)map最多處理一個(gè)HDFS 文件。 這意味著假如應(yīng)用需要處理大量的文件,最好一個(gè)map能夠處理多個(gè)??梢酝ㄟ^(guò)一種特定的輸入格式來(lái)達(dá)成這個(gè)目的,就是MultiFileInputFormat。即使對(duì)于那些只處理很少小文件的應(yīng)用,每個(gè)map處理多個(gè)文件的效率也更高。
- 假如應(yīng)用需要處理的數(shù)據(jù)量非常大,即使文件尺寸很大,每個(gè)map處理128M以上的數(shù)據(jù)也會(huì)更有效率。
網(wǎng)格模式: 合并小文件以減少map數(shù)量,在處理大數(shù)據(jù)集的時(shí)候用比較大的HDFS 塊大小。
Maps
maps的數(shù)量通常取決于輸入大小, 也即輸入文件的block數(shù)。 因此,假如你的輸入數(shù)據(jù)有10TB,而block大小為128M,則需要82,000個(gè)map。
因?yàn)閱?dòng)任務(wù)也需要時(shí)間,所以在一個(gè)較大的作業(yè)中,最好每個(gè)map任務(wù)的執(zhí)行時(shí)間不要少于1分鐘。
就像在上面“輸入”部分所解釋的,對(duì)于那種有大量小文件輸入的的作業(yè)來(lái)說(shuō),一個(gè)map處理多個(gè)文件會(huì)更有效率。
如果應(yīng)用處理的輸入文件尺寸較大,每個(gè)map處理一個(gè)完整的HDFS block,數(shù)據(jù)段大一點(diǎn)更有效率。舉個(gè)例子,讓每個(gè)map處理更多數(shù)據(jù),方法之一是讓輸入文件有更大的HDFS block尺寸,例如512M或者更多。
一個(gè)極端的例子是Map-Reduce開(kāi)發(fā)團(tuán)隊(duì)用了大約66000個(gè)map來(lái)做PetaSort,也即66000個(gè)map要處理1PB數(shù)據(jù),平均每個(gè)map 12.5G。
原則是大量運(yùn)行時(shí)間很短的map會(huì)有損生產(chǎn)力。
網(wǎng)格模式:除非應(yīng)用的map過(guò)程是CPU密集型,否則一個(gè)應(yīng)用不應(yīng)該有60000-70000個(gè)map。
當(dāng)在map處理的block比較大的時(shí)候,確保有足夠的內(nèi)存作為排序緩沖區(qū)是非常重要的,這可以加速map端的排序過(guò)程。假如大多數(shù)的map輸出都能在排序緩沖區(qū)中處理的話(huà)應(yīng)用的性能會(huì)有極大的提升。這需要運(yùn)行map過(guò)程的JVM具有更大的堆。記住反序列化輸入的內(nèi)存操作不同于磁盤(pán)操作;例如,Pig應(yīng)用中的某些class將硬盤(pán)上的數(shù)據(jù)載入內(nèi)存之后占用的空間會(huì)是其本來(lái)尺寸的3、4倍。在這種情況下,應(yīng)用需要更大的JVM堆來(lái)讓map的輸入和輸出數(shù)據(jù)能夠保留在內(nèi)存中。
網(wǎng)格模式:確保map的大小,使得所有的map輸出可以在排序緩沖區(qū)中通過(guò)一次排序來(lái)完成操作。
合適的map數(shù)量有以下好處:
- 減少了調(diào)度的負(fù)擔(dān);更少的map意味著任務(wù)調(diào)度更簡(jiǎn)單,集群中可用的空閑槽更多。
- 有足夠的內(nèi)存將map輸出容納在排序緩存中,這使map端更有效率;
- 減少了需要shuffle map輸出的尋址次數(shù),每個(gè)map產(chǎn)生的輸出可用于每一個(gè)reduce,因此尋址數(shù)就是map個(gè)數(shù)乘以reduce個(gè)數(shù);
- 每個(gè)shuffled的片段更大,這減少了建立連接的相對(duì)開(kāi)銷(xiāo),所謂相對(duì)開(kāi)銷(xiāo)是指相對(duì)于在網(wǎng)絡(luò)中傳輸數(shù)據(jù)的過(guò)程。
- 這使reduce端合并map輸出的過(guò)程更高效,因?yàn)楹喜⒌拇螖?shù)更少,因?yàn)樾枰喜⒌奈募胃倭恕?/li>
上述指南需要注意,一個(gè)map處理太多的數(shù)據(jù)不利于失敗轉(zhuǎn)移,因?yàn)閱蝹€(gè)map失敗可能會(huì)造成應(yīng)用的延遲。
Combiner
適當(dāng)?shù)氖褂肅ombiner可以?xún)?yōu)化map端的聚合。Combiner最主要的好處在于減少了shuffle過(guò)程從map端到reduce端的傳輸數(shù)據(jù)量。
Shuffle
適當(dāng)?shù)氖褂肅ombiner可以?xún)?yōu)化map端的聚合。Combiner最主要的好處在于減少了shuffle過(guò)程從map端到reduce端的傳輸數(shù)據(jù)量。
Combiner 也有一個(gè)性能損失點(diǎn),因?yàn)樗枰淮晤~外的對(duì)于map輸出的序列化/反序列化過(guò)程。不能通過(guò)聚合將map端的輸出減少到20-30%的話(huà)就不適用combiner??梢杂?combiner input/output records counters(譯者注:這是一個(gè)hadoop mapreduce 的counter名稱(chēng),所以采用了原名未翻譯)來(lái)衡量Combiner的效率。
網(wǎng)格模式:Combiners可以減少shuffle階段的網(wǎng)絡(luò)流量。但是,要保證Combiner 的聚合是確實(shí)有效的。
Reduces
reduces的性能很大程度上受shuffle的性能所影響。
應(yīng)用配置的reduces數(shù)量是一個(gè)決定性的因素。
太多或者太少的reduce都不利于發(fā)揮最佳性能:
- 太少的reduce會(huì)使得reduce運(yùn)行的節(jié)點(diǎn)處于過(guò)度負(fù)載狀態(tài),在極端情況下我們見(jiàn)過(guò)一個(gè)reduce要處理100g的數(shù)據(jù)。這對(duì)于失敗恢復(fù)有著非常致命的負(fù)面影響,因?yàn)槭〉膔educe對(duì)作業(yè)的影響非常大。
- 太多的reduce對(duì)shuffle過(guò)程有不利影響。在極端情況下會(huì)導(dǎo)致作業(yè)的輸出都是些小文件,這對(duì)NameNode不利,并且會(huì)影響接下來(lái)要處理這些小文件的mapreduce應(yīng)用的性能。
網(wǎng)格模式:在大多數(shù)情況下,應(yīng)用應(yīng)該保證每個(gè)reduce處理1-2g數(shù)據(jù),最多5-10g。
輸出
我們需要記住一個(gè)重要的因素——應(yīng)用的輸出文件數(shù)取決于配置的reduce數(shù)。從我們上文中對(duì)reduce的討論可知,reduce數(shù)的選擇十分關(guān)鍵。
此外,還需要考慮其它一些因素:
- 考慮采用合適的壓縮器(壓縮速度vs性能)對(duì)輸出進(jìn)行壓縮,提高HDFS的寫(xiě)入性能。
- 每個(gè)reduce不要輸出多個(gè)文件,避免生成附屬文件。我們一般用附屬文件來(lái)記錄統(tǒng)計(jì)信息,如果這些信息不多的話(huà),可以使用計(jì)數(shù)器。
- 為輸出文件選擇合適的格式。對(duì)于下游消費(fèi)者程序來(lái)說(shuō),用zlib/gzip/lzo等算法來(lái)對(duì)大量文本數(shù)據(jù)進(jìn)行壓縮往往事與愿違。因?yàn)閦lib/gzip/lzo文件是不能分割的,只能整個(gè)進(jìn)行處理。這會(huì)引起惡劣的負(fù)載均衡和故障恢復(fù)問(wèn)題。作為改善,可以使用SequenceFile和TFile格式,它們不但是壓縮的,而且是可以分割的。
- 如果每個(gè)輸出文件都很大(若干GB),請(qǐng)考慮使用更大的輸出塊(dfs.block.size)。
網(wǎng)格模式: 應(yīng)該確保應(yīng)用的輸出是數(shù)量不多的大文件,每個(gè)文件跨越多個(gè)HDFS塊,而且經(jīng)過(guò)適當(dāng)?shù)膲嚎s。
分布式緩存(Distributed Cache)
分布式緩存可以高效的分發(fā)與具體應(yīng)用相關(guān)的較大尺寸的只讀文件。這是Map/Reduce框架提供的機(jī)制,用于暫時(shí)存儲(chǔ)與特定應(yīng)用相關(guān)的文件(如text, archives, jars等)。
這個(gè)框架會(huì)在slave節(jié)點(diǎn)上執(zhí)行任務(wù)之前將必要的文件拷貝到該節(jié)點(diǎn)。它如此高效是因?yàn)樵趥€(gè)作業(yè)中所需要的文件只會(huì)被復(fù)制一遍,還因?yàn)樗軌蚓彺鎠lave節(jié)點(diǎn)上的未歸檔文件。它也被作為基本軟件分發(fā)機(jī)制用于map和reduce 任務(wù)。這種機(jī)制可以把jar和本地庫(kù)放置在map/reduce任務(wù)的classpath或者本地庫(kù)路徑下。
分布式緩存設(shè)計(jì)之初是為了分發(fā)一些尺寸不是很大,從幾M到幾十M的附件。目前實(shí)現(xiàn)的分布式緩存的弱點(diǎn)在于不能夠指定具體的附件只能應(yīng)用于特定的map或者reduce。
在極少數(shù)情況下,由具體任務(wù)本身來(lái)拷貝其所需的附件要比使用分布式緩存更合適。例如,那種reduce數(shù)很少的應(yīng)用,而且需要的附屬文件尺寸非常大(超過(guò)512M)。
網(wǎng)格模式:應(yīng)用應(yīng)該保證分布式緩存中的附件不能夠比任務(wù)本身的I/O消耗更多。
壓縮
Hadoop Map-Reduce 可以在應(yīng)用中對(duì)map輸出的中間數(shù)據(jù)和reduce的輸出數(shù)據(jù)進(jìn)行指定的壓縮。
- 壓縮中間數(shù)據(jù): 正如在 shuffle 部分所講的,對(duì)map輸出的中間數(shù)據(jù)進(jìn)行合適的壓縮可以減少map到reduce之間的網(wǎng)絡(luò)數(shù)據(jù)傳輸量,從而提高性能。Lzo 壓縮格式是一個(gè)壓縮map中間數(shù)據(jù)的合理選擇,它有效利用了CPU。
- 壓縮應(yīng)用輸出:就如在 輸出 部分所講的, 使用合適的壓縮格式壓縮輸出數(shù)據(jù)能夠減少應(yīng)用的運(yùn)行時(shí)間。Zlib/Gzip 格式在大多數(shù)情況下都是比較適當(dāng)?shù)倪x擇,因?yàn)樗谳^高壓縮率的情況下壓縮速度也還算可以,bzip2 就慢得多了。
全排序輸出
抽樣
有時(shí)候,應(yīng)用需要產(chǎn)生全排序的輸出。在這種情況下,一個(gè)通用的反模式是只使用一個(gè)reduce,這樣就能強(qiáng)制數(shù)據(jù)集中在一處做聚合。很明顯,這樣做效率不高,這樣不僅加大了執(zhí)行reduce的那個(gè)節(jié)點(diǎn)的負(fù)載,還對(duì)失敗恢復(fù)有嚴(yán)重的不良影響。
更好的辦法是對(duì)輸入抽樣,然后以此來(lái)使用sampling partitioner 代替默認(rèn)的hash partitioner。這樣可以獲得更好的負(fù)載平衡和失敗恢復(fù)。#p#
連接(join)有序數(shù)據(jù)集
另一種網(wǎng)格設(shè)計(jì)模式是關(guān)于兩個(gè)有序數(shù)據(jù)集的連接,其中一個(gè)數(shù)據(jù)集的大小并非另一個(gè)的嚴(yán)格倍數(shù)。例如,一個(gè)數(shù)據(jù)集有512個(gè)buckets,另一個(gè)有200個(gè)。
在這種情況下,確保輸入的數(shù)據(jù)集是整體有序的(全排序,如同在商議部分所提到的)意味著可以使用兩個(gè)數(shù)據(jù)集中的任意一個(gè)來(lái)作為基數(shù)。Pig 就是用這種發(fā)發(fā)來(lái)進(jìn)行高效的連接。
HDFS 操作 & JobTracker 操作
NameNode 很重要而且負(fù)擔(dān)要比一般的節(jié)點(diǎn)重,所以在進(jìn)行HDFS 操作的時(shí)候要注意對(duì)性能的影響。特別是,應(yīng)用程序不要在map/reduce任務(wù)中做非I/O操作,也即像遍歷目錄,遞歸統(tǒng)計(jì)等這樣的元數(shù)據(jù)操作。
同樣,不要在應(yīng)用程序中連接JobTracker來(lái)獲得關(guān)于集群統(tǒng)計(jì)的數(shù)據(jù)。
網(wǎng)格模式:應(yīng)用不應(yīng)該在代碼中執(zhí)行任何文件系統(tǒng)的元數(shù)據(jù)操作,這種操作應(yīng)該在作業(yè)提交的時(shí)候被嚴(yán)格禁止。除此以外,應(yīng)用程序不應(yīng)該自己連接JobTracker 。
User Logs
與用戶(hù)執(zhí)行的任務(wù)相關(guān)的task-logs,也即 map/reduce 任務(wù)的標(biāo)準(zhǔn)輸出和錯(cuò)誤信息儲(chǔ)存在執(zhí)行這個(gè)任務(wù)的節(jié)點(diǎn)的本地磁盤(pán)上。
因?yàn)槊總€(gè)節(jié)點(diǎn)都是共享存儲(chǔ)的一部分,所以Map-Reduce 框架對(duì)儲(chǔ)存在節(jié)點(diǎn)上的log數(shù)量實(shí)際上是有限制的。
Web界面
Hadoop Map-Reduce 框架提供了一個(gè)簡(jiǎn)單的web界面來(lái)監(jiān)控運(yùn)行中的作業(yè),查看已完成作業(yè)的歷史,以及其他一些從JobTracker獲得的信息
要明白這個(gè)web界面是給人看的而不是自動(dòng)程序。
通過(guò)一些屏幕自動(dòng)化軟件來(lái)從web界面獲取信息是不可行的。web界面上的某些部分,像查看歷史作業(yè),非常消耗JobTracker 的資源,如果使用屏幕自動(dòng)化軟件這么做可能會(huì)導(dǎo)致一些性能問(wèn)題。
假如真有這么一個(gè)自動(dòng)統(tǒng)計(jì)匯總的需求,最好去咨詢(xún) Map-Reduce的開(kāi)發(fā)團(tuán)隊(duì)。
工作流
Oozie 是一個(gè)適用于網(wǎng)格應(yīng)用的非常好的工作流管理和調(diào)度系統(tǒng)。Oozie 可以基于時(shí)間或者數(shù)據(jù)可用性來(lái)管理和計(jì)劃工作流。使用Oozie來(lái)管理和調(diào)度的低延遲要求的,產(chǎn)品級(jí)的項(xiàng)目已經(jīng)越來(lái)越多。
設(shè)計(jì)Oozie 的時(shí)候考慮的一個(gè)重要因素是Hadoop 更適宜于批量處理大量數(shù)據(jù)。正因如此,用幾個(gè)中等規(guī)模的Map-Reduce組成處理流程,要比用更多的小型的Map-Reduce作業(yè)更好。在極端情況下一個(gè)流程可能由幾百上千個(gè)作業(yè)組成,這是很明顯的反模式。更好的做法是能夠?qū)⑦@些Map-Reduce作業(yè)重新組裝成較少的幾個(gè)過(guò)程,每個(gè)過(guò)程處理更多的數(shù)據(jù),這有助于提高整個(gè)流程的性能并降低延遲。
網(wǎng)格模式:工作流中一個(gè)Map-Reduce作業(yè)應(yīng)該至少處理十幾G數(shù)據(jù)。
反模式
這部分會(huì)總結(jié)一些網(wǎng)格應(yīng)用通用的反模式。這些東西大多數(shù)情況下都與大規(guī)模、分布式、批量數(shù)據(jù)處理系統(tǒng)的原則相悖。這是對(duì)應(yīng)用開(kāi)發(fā)人員的提醒,因?yàn)榫W(wǎng)格軟件逐漸規(guī)范化固定化,特別是即將發(fā)布的20.Fred版本,對(duì)于具有下面列出的這些反模式的應(yīng)用更難容忍。
- 不愛(ài)使用像Pig這樣的高層次抽象接口。
- 處理幾千個(gè)小文件(小于1個(gè)block的大小,一般是128M),一個(gè)map只能處理一個(gè)小文件。
- 處理大量數(shù)據(jù)的,但HDFS block比較小,導(dǎo)致產(chǎn)生數(shù)萬(wàn)個(gè)map。
- map數(shù)量非常多,每個(gè)map的運(yùn)行時(shí)間卻非常短(例如5秒)。
- 簡(jiǎn)單聚合卻不用Combiner。
- 產(chǎn)生的map數(shù)量多于6、7萬(wàn)。
- 處理大數(shù)據(jù)集的時(shí)候只用很少的reduce(例如只用1個(gè))。
- 用Pig 腳本處理大數(shù)據(jù)集的時(shí)候沒(méi)有用PARALLEL關(guān)鍵字。
- 用1個(gè)reduce為所有輸出進(jìn)行全局排序。
- 用很多reduce來(lái)處理數(shù)據(jù),以致每個(gè)reduce只能處理1-2G數(shù)據(jù)。
- 輸出文件多且小。
- 用分布式緩存分發(fā)過(guò)多的文件或過(guò)大的文件(幾百M(fèi))。
- 一個(gè)任務(wù)有幾十上百個(gè)計(jì)數(shù)器。
- 在map/reduce 任務(wù)理執(zhí)行文件系統(tǒng)元數(shù)據(jù)操作(例如 listStatus)。
- 用屏幕自動(dòng)化軟件來(lái)收集web界面上的信息,作業(yè)、隊(duì)列狀態(tài),更糟的是查看已完成作業(yè)的歷史。
- 工作流由成百上千個(gè)小作業(yè)做成,每個(gè)都只處理少量數(shù)據(jù)。
英文原文:Apache Hadoop: Best Practices and Anti-Patterns