4.MapReduce模板開發(fā)

1. mapreduce程序介紹:

mapreduce是Google提出的一種計(jì)算框架。框架處理key、value對;數(shù)據(jù)處理過程中數(shù)據(jù)流向格式。

mapreduce程序開發(fā)包含三個(gè)部分:

(1)map:分布到很多節(jié)點(diǎn)上去執(zhí)行;

(2)reduce:合并map的輸出結(jié)果

(3)Job: job調(diào)度配置。

Input --> ?Map ?--> ?Reduce --> Output

2. wordcount思路:

假設(shè)對下邊這個(gè)文件wc.txt,進(jìn)行詞頻統(tǒng)計(jì)(分隔符是制表符):

SF LUNA LION

LUNA NEC LION

SF SF POM

將該文件上傳到 HDFS 上:

$cd $HADOOP_HOME

$bin/hdfs dfs -put /home/natty.ma/bigdata/hadoop/files/wordcountfiles.txt /user/natty.ma/hdfsapi/

$bin/hdfs dfs -text /user/natty.ma/hdfsapi/wordcountfiles.txt

(1)在Input階段,MapReduce內(nèi)部的FileInputFormat會(huì)將文件處理成“<偏移量,本行內(nèi)容>”這種key value的格式。

那么Input階段會(huì)生成下邊的結(jié)果:

<13,SF LUNA LION>?

<26,LUNA NEC LION>

<37,SF SF POM>

(2)在Map階段,輸入是第(1)步的輸出。將每行記錄內(nèi)容按照制表符拆分出單詞,并把拆分出的單詞作為key,value給1。

這樣得到的key value對是:

<SF,1>

<LUNA,1>

<LION,1>

<LUNA,1>

...

(3)在Reduce階段,合并每個(gè)key的多個(gè)值。

在MR內(nèi)部,會(huì)將相同的Map階段的key 的value值合并成list(Iterable)。得到下面的key value對:

<LION,(1,1)>

<LUNA,(1,1)>

<NEC,(1)>

<POM,(1)>

<SF,(1,1,1)>

上邊的集合作為Reduce階段的輸入,在reduce階段,將value值的list的值合并(sum)。Reduce的輸出是:

<LION,2>

<LUNA,2>

<NEC,1>

<POM,1>

<SF,3>

3.程序?qū)崿F(xiàn):

下面是按照規(guī)范實(shí)現(xiàn)的示例程序:

WordCountMapReduce.java

上邊程序?qū)崿F(xiàn)了WordCount的邏輯。主要包含4個(gè)部分:創(chuàng)建 Mapper類、創(chuàng)建Reducer類、配置Job、提交Job

4.提煉模板:

MapReduce也是“八股文”變成模式,最終要的是分析MapReduce要實(shí)現(xiàn)的業(yè)務(wù)邏輯,從而確定Map和Reduce階段的業(yè)務(wù)邏輯。

確定Map階段的輸入輸出、Reduce階段的輸入和輸出。確定Map和Reduce的參數(shù)(LongWritable、IntWritable、Text等)。

提煉了模板需要修改以下地方:

(1)Mapper和Reducer的類名(根據(jù)業(yè)務(wù)實(shí)際含義)

(2)Mapper類的輸入、輸出類型(輸入的key、value;輸出的key、value)。

(3)Reducer類的輸入、輸出類型(輸入的key、value;輸出的key、value)。

(4)Mapper類重寫的map方法輸入類型。map()方法的前2個(gè)參數(shù)是map的輸入key、value。輸出key、value寫入context中。

(5)Reducer類重寫的reduce方法的輸入類型。reduce()方法的前2個(gè)參數(shù)是reduce的輸入key、value。輸出key、value寫入context中。

(6)job設(shè)置mapper和reducer類 及其key、value類型。

下面是整理的模板類:

ModuleWordCountMapReduce

5. WebPV事例程序研究:

該事例使用一個(gè)樣本文件,以TAB鍵分割數(shù)據(jù)。數(shù)據(jù)字典:


WebPV數(shù)據(jù)文件數(shù)據(jù)字典

計(jì)數(shù)每一個(gè)省份代碼(provinceId)有效的URL數(shù)量。首先,清洗每條記錄,保留合法記錄(例如,url不能為空,必須要有provinceId字段,provinceId字段需要是數(shù)字等條件)。清洗出所有合法的記錄后,統(tǒng)計(jì)每個(gè)省份代碼出現(xiàn)的次數(shù),也就是該省份PV數(shù)量了。

下面WebPV的MapReduce程序?qū)崿F(xiàn)了上述邏輯:

WebPVMapReduce.java

6. Shuffle 階段:

Shuffle描述的是從Map輸出到Reduce輸入的中間過程。Shuffle包含Map端ShuffleReduce端Shuffle。這中間的過程是:

Input ?--> ?map()階段 --> ?map階段output --> map端Shuffle --> Reduce端Shuffle --> Reduce階段Input?


MapReduce中的shuffle和sort

6.1 Map端Shuffle處理:

map()函數(shù)產(chǎn)生的map的Output不是直接寫到磁盤,而是在內(nèi)存中緩存并進(jìn)行預(yù)排序。每個(gè)map任務(wù)有環(huán)形內(nèi)存緩沖來保存map輸出。這個(gè)內(nèi)存空間默認(rèn)是100MB(通過mapreduce.task.io.sort.mb來配置),但是如果這個(gè)緩沖內(nèi)存占滿了,就需要往磁盤上寫了,這個(gè)過程叫做spill。但是一般情況下,達(dá)到一個(gè)閾值就會(huì)開始spill(溢出),默認(rèn)是80%,通過mapreduce.map.sort.spill.percent 來配置。 寫在運(yùn)行map的節(jié)點(diǎn)的本地,目錄有下邊屬性配置:mapreduce.cluster.local.dir。

備注:(當(dāng)緩沖區(qū)快滿時(shí),會(huì)寫到磁盤生成一個(gè)臨時(shí)文件。當(dāng)這個(gè)map task結(jié)束后,會(huì)對磁盤上這個(gè)map task產(chǎn)生的所有臨時(shí)文件進(jìn)行排序、合并,并生成最終的輸出文件,等待reduce task來拉取數(shù)據(jù)。)

Partition、Sort、Combine、Merge、Compress:

在寫入磁盤前,會(huì)將數(shù)據(jù)分為不同的分區(qū),每個(gè)分區(qū)對應(yīng)一個(gè)reducer(也就是說分配到同一個(gè)partition的數(shù)據(jù)會(huì)由同一個(gè)reducer來處理)。在同一個(gè)分區(qū)內(nèi),數(shù)據(jù)會(huì)按照key來排序,如果有combiner函數(shù)的話,也會(huì)執(zhí)行在sort的輸出結(jié)果上。Combiner函數(shù)會(huì)先對map結(jié)果進(jìn)行合并(例如sum),這樣使得臨時(shí)文件中的數(shù)據(jù)大大減少,臨時(shí)文件也就會(huì)變小,進(jìn)而減少在集群中數(shù)據(jù)轉(zhuǎn)移量,減少I/O,提高效率。由于每次緩沖器達(dá)到閾值時(shí),都會(huì)生成一個(gè)新的臨時(shí)文件,所以很可能有很多臨時(shí)文件,這些文件最終會(huì)合并成一個(gè)單獨(dú)的分區(qū)的、排序的output文件。

生成的spill文件數(shù)量如果大于3個(gè),會(huì)再次調(diào)用combiner。如果只有1個(gè)或者2個(gè)spill文件,那么combiner就不再值得使用來降低map output文件的大小,所以combiner就不再執(zhí)行了。

在map output寫入磁盤前,做壓縮可以優(yōu)化性能。文件壓縮后變小,寫入磁盤更快,文件在拷貝到其他reducer的節(jié)點(diǎn)的時(shí)間也會(huì)縮短。默認(rèn)是不做壓縮的。可以修改屬性 :mapreduce.map.output.compress

6.2 Reduce端Shuffle處理:

1.Copy階段:

Map階段的mapoutput放在執(zhí)行map任務(wù)的機(jī)器的本地目錄(local dir)上。如果mapoutput分了多個(gè)partition。假如,mapoutput輸出文件中分區(qū)到partition1的數(shù)據(jù),就需要拷貝到reducer1執(zhí)行所在的機(jī)器。并且,reducer1需要的文件,會(huì)來自多個(gè)不同的map tasks(同時(shí)也就來自多個(gè)節(jié)點(diǎn)),這些map tasks完成時(shí)間不同,只要map task完成,reducer就會(huì)立即copy數(shù)據(jù)。

Reduce Task在copy data時(shí),如果數(shù)據(jù)較小會(huì)直接copy在內(nèi)存中,如果超過閾值,存在磁盤上。當(dāng)拷貝在磁盤上累積時(shí),后臺程序會(huì)做merge和sort。(當(dāng)然,這個(gè)是在同一個(gè)Reduce Task中做的處理,也肯定是同一個(gè)分區(qū)的數(shù)據(jù))

2. Sort階段:

map outputs拷貝完成后,進(jìn)入sort階段。該階段合并來自不同 map tasks的 map outputs并保持排序。Sort階段分多輪進(jìn)行 ,假如有50個(gè)map outputs,并且 merge參數(shù)設(shè)為10(通過mapreduce.task.io.sort.factor 屬性設(shè)定)。那么會(huì)有5個(gè)中間臨時(shí)文件。Merge階段不會(huì)把這些文件合成為一個(gè)文件傳遞給reduce階段,而是把這5個(gè)中間臨時(shí)文件直接傳給reduce,reduce階段再對這5個(gè)中間臨時(shí)文件執(zhí)行reduce函數(shù)。

3. Reduce階段:

在Reduce階段,Reduce函數(shù)在每個(gè)已排序的output文件上的每個(gè)key使用,reduce的output直接寫到HDFS。該階段進(jìn)行g(shù)roup,相同key的value組合在一起 ,例如:<hadoop,(1,1,1)>。

6.3 mapreduce優(yōu)化:

shuffle是mapreduce的核心,優(yōu)化mapreduce程序也就是優(yōu)化shuffle階段,優(yōu)化一些shuffle階段使用的參數(shù)。在優(yōu)化時(shí),可以重點(diǎn)優(yōu)化shuffle過程中的下面幾個(gè)階段:

partition

sort

combine

compress

group

7. 自定義數(shù)據(jù)類型

Writable接口(org.apache.hadoop.io.Writable):一個(gè)實(shí)現(xiàn)簡單、高效、序列化協(xié)議的序列化對象。

在MapReduce中,value必須實(shí)現(xiàn)Writable接口。

在MapReduce中,key必須實(shí)現(xiàn)WritableComparable接口。 WritableComparable接口繼承Writable和Comparable<T>。

下面的類自定義了數(shù)據(jù)類型 CustomDataWritable。包含5個(gè)屬性:上下行數(shù)據(jù)包、上下行流量、電話號碼個(gè)數(shù)計(jì)數(shù)。

CustomDataWritable.java

8. 手機(jī)流量案例統(tǒng)計(jì)

手機(jī)流量案例(日志文件),數(shù)據(jù)字典:

日志文件數(shù)據(jù)字典

如上邊數(shù)據(jù)文件的數(shù)據(jù)字典,統(tǒng)計(jì)每一個(gè)手機(jī)號的 上行數(shù)據(jù)包總數(shù)、下行數(shù)據(jù)包總數(shù)、上行總流量數(shù)、下行總流量數(shù)。?

那么其實(shí)思路非常清晰,我們篩選出符合條件的數(shù)據(jù)記錄。按照手機(jī)號碼(msisdn)來sum上邊4個(gè)指標(biāo)就可以了。非常簡單! 在用mapreduce來實(shí)現(xiàn)時(shí),我們需要?jiǎng)?chuàng)建一個(gè)“自定義數(shù)據(jù)類型” , 這個(gè)類型包含以下四個(gè)屬性:

upPackNum;

downPackNum;

upPayLoad;

downPayLoad;

這樣一簡化之后,我們就可以按照key(手機(jī)號碼),Reduce我們的自定義數(shù)據(jù)類型就可以了。

下面程序?qū)崿F(xiàn)了按手機(jī)號統(tǒng)計(jì)流量的邏輯(最后一位是該手機(jī)號出現(xiàn)的次數(shù)):

PhoneStatisticsMapReduce.java

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容