一、單選題
1、Shuffle中Partitioner 分區發生在哪個過程( A )
A. 溢寫過程
B. 本地Merge
C. reduce函數階段
D. map函數階段
2、在整個maprduce運行階段,數據是以( A )形式存在的
A. key/value
B. LongWritable
C. Text
D. IntWritable
3、下列哪個方法提交job任務的入口方法 ( B )
A. JoB.addCacheFile()
B. JoB.waitForCompletion()
C. JoB.setMapperClass()
D. JoB.setJarByClass()
二、多選題
1、下列哪些是對reduceTask階段任務正確理解(ABC )
A. 對多個mapTask任務輸出key,value,按照不同的分區通過網絡copy到不同的reduceTask節點處理。
B. 對多個mapTask任務的輸出進行合並、排序。再reduce函數中實現自己的邏輯,對輸入的key、value處理,轉換成新的key、value輸出。
C. outputformat把reducer輸出的key,value保存到文件中。
D. reduceTask階段不會根據key進行分組和排序
2、執行一個job, 如果這個job的輸出路徑已經存在,那么程序會 ( CD )
A. 覆蓋這個輸出路徑
B. 拋出警告,但是能夠繼續執行
C. 拋出一個異常,然后退出程序的執行
D. 會拋出文件路徑已存在的異常
3、對mapreduce數據類型理解正確(AB )
A. Java中的String類型在Mapreduce中對應的是Text類型
B. hadoop的序列化,對象可以被序列化成二進制字節序列進行網絡傳輸和存儲
C. Mapreduce中的數據類型和java一模一樣
D. Mapreduce中的數據類型完全和java中基本類型是通用的
4、下列說法正確的是(ABC )
A. mapreduce總體上分為maptask階段和reducetask階段
B. shfflue階段由maptask的map方法之后的部分和reduce方法之前前部分組成
C. shfflue階段可能會造成數據傾斜
D. shfflue階段不會對數據進行排序和分區
5、下列說法正確的是 ( BCD )
A. inputformat階段會對文件進行切片,切片過程是物理上的切片,切切實實的對數據進行了分割
B. mr中默認使用的是TextInputFormat對文件進行讀取,一次讀取一行,偏移量作為key值,行內容作為value值對應的數據類型為LongWritable和Text
C. mapreduce運行過程中切片的數量決定了maptask的數量,maptask任務並行執行互不影響。
D. inputformat會將文件轉換為(key, value)值得形式輸出到mapper類的map()方法中
6、下列描述正確的是(ABC )
A. 默認的reduceTask數量為1意味着所有的mapTask處理后的數據都會交給這個reduceTask進行數據的匯總,最終輸出一個文件
B. 當分區數量大於reduceTask數量時,程序運行出錯
C. 自定義分區首先需要定義一個類,繼承自Partitioner,實現getPartition()方法根據具體需求返回對於的分區號。
D. ReduceTask的數量越多越好,這樣處理數據執行的效率越高
三、判斷題
1、如果reduceTask存在多個,那么單個ReduceTask負責從不同MapTask上拷貝同一分區數據最終對數據進行歸並排序和分組,將數據一組一組的傳遞給Reducer類中的reduce方法中進行處理(對 )
2、MapReduce是一個分布式的運算程序編程框架,適合處理大量的離線數據,有良好的擴展性和高容錯性( 對 )
3、在整個mapreduce階段共實現了2次排序(錯)
4、在整個Shufflue過程中環形緩沖區得大小默認為100M,存儲量達到百分之80則完成溢寫,將內存中得數據寫入到磁盤中(對 )
5、 使用hadoop-daemon.sh start/stop resourcemanager 命令啟動和停止resourcemanager ( 對 )
四、簡答題
1、簡單描述Shuffle過程環形緩沖區的作用(shuffle流程概述)?
[答案]key,value從map()方法輸出后,被outputcollector收集通過HashPartitioner類的getpartitioner()方法獲取分區號,進入環形緩沖區。默認情況下,環形緩沖區為100MB。當環形環形緩沖區存儲達到80%,開始執行溢寫過程,溢寫過程中如果有其他數據進入,那么由剩余的20%反向寫入。溢寫過程會根據key,value先根據分區進行排序,再根據key值進行排序,后生成一個溢寫文件(再對應的分區下根據key值有序),maptask將溢寫文件歸並排序后落入本地磁盤,reduceTask階段將多個mapTask下相同分區的數據copy到指定的reduceTask中進行歸並排序、分組后一次讀取一組數據給reduce()函數。
2、mapreduce在哪些階段(位置)實現了排序?默認是怎么排序的?如何自定義排序?
[答案](1)MapTask和ReduceTask均會對數據按照key進行排序。
MapTask,會將處理的結果暫時放到環形緩沖區中,當環形緩沖區使用率達到一定閾值(100M的百分之80)后,對緩沖區中的數據進行一次快速排序,並將有序數據溢寫到磁盤上,最后會對磁盤上所有文件溢寫文件進行歸並排序。
ReduceTask,從每個MapTask上拷貝對應分區的數據文件,如果文件大小超過一定閾值,則溢寫磁盤上,否則存儲在內存中。當所有數據拷貝完畢后,ReduceTask統一對內存和磁盤上的所有數據進行一次歸並排序。
(2)排序操作屬於Hadoop的默認行為。任何應用程序中的數據均會被排序,默認排序是按照字典順序排序,實現該排序的方法是快速排序。
(3)我們需要在數據對象類中實現WritableComparable接口中的 compareTo方法(自然比較方法),從而實現對當前對象和傳入對象的比對,實現排序。
3、Combiner是什么有什么作用?Combiner的作用位置和Reducer的作用位置有什么不同?
[答案](1)Combiner是MR程序中Mapper和Reducer之外的一種組件,繼承自reducer,是可選的,並不是必須存在的,因為只有在不影響最終業務結果的場景下才能使用。Combiner的作用就是對每一個MapTask的輸出進行局部匯總,以減小網絡傳輸量
(2)Combiner是在每一個MapTask所在的節點運行;Reducer是接收全局所有Mapper的輸出結果
4、hadoop序列化的特點?如何實現序列化?序列化和反序列化時要注意什么?
[答案](1) hadoop序列化之序列化必要數據,所以具有緊湊、快速高效、可擴展、互操作的特點,
(2)必須實現Writable接口,重寫序列化public void write(DataOutput out)方法和反序列化public void readFields(DataInput in)方法
(3)序列化時要注意數據的數據類型,注意反序列化的順序和序列化的順序完全一致
5、mapreduce處理數據時FileInputFormat中getSplits()方法是如何對數據進行切片的?
[答案] 默認情況下為了避免mr處理數據的過程中存在網絡數據傳輸,從而降低mr的效率,默認的切片大小為block塊大小(128M),FileInputFormat中getSplits()方法會根據文件大小將文件拆分成splits,如果單個文件較小小於128的1.1倍,則每個文件為一個split,並將文件按行分割形成<key,value>對,如果單個文件較大。超過block塊(128M)默認大小得1.1倍,則會將文件切分為多個split,切片數量決定了maptask的任務數量。
6、mr默認的reduceTask數量是多少?mr默認是如何為key,value分配分區的?總結如何自定義分區?使用自定義分區的注意事項(reducetask和分區的關系)?
(1)默認的reduceTask數量為1意味着所有的mapTask處理后的數據都會交給這個reduceTask進行數據的匯總,最終輸出一個文件
(2)數據在經過map方法的context.write()寫出后,會通過outputcollector收集,底層調用HashPartitioner類的getPartition()方法通過(key.hashCode() & Integer.MAX_VALUE) % numReduceTasks模得到的,但是用戶沒法控制哪個key存儲到哪個分區。
(3)自定義分區首先需要定義一個類,繼承自Partitioner,實現getPartition()方法根據具體需求返回對於的分區號,最后通過job.setPartitionerClass()設置分區類
1 public class FlowPartitioner extends Partitioner<Text,FlowBean> { 2 public int getPartition(Text text, FlowBean flowBean, int numPartitions) { 3 //分區號從0開始:5reducetask 5個分區:0~4 4 //手機號136、137、138、139開頭都分別放到一個獨立的4個文件中, 5 //其他開頭的放到一個文件中。
6 String phonenum = text.toString(); 7 switch (phonenum.substring(0,3)){ 8 case "136": 9 return 0; 10 case "137": 11 return 1; 12 case "138": 13 return 2; 14 case "139": 15 return 3; 16 default: 17 return 4; 18 } 19 } 20 }
(4)注意:
分區號從0開始,不要跳號
當分區數量大於reduceTask數量時,程序運行出錯
當設置reduceTask的數量為一時,不走分區方法
當設置的reduceTask數量大於分區時,會產生空的輸出文件
7、如何實現根據bean對象中的某一個值進行分組?
此場景我們通常使用的是輔助分組,定義類繼承自WritableComparator,重寫compare()方法通過對象中的某一個或者多個參數比對,參數相同則視為同一組數據進入到reduce方法中。
注意:使用時需要創建一個構造器將比較對象的類傳給父類(不然會報出Null..空指針異常)
8、job提交流程步驟:
waitForCompletion 提交job 任務的入口方法
if(state == JobState.DEFINE)判斷任務是否處於定義狀態
submit();
ensureState(JobState.DEFINE); //再次確認任務狀態(不是DEFINE狀態則拋出異常)
setUseNewAPI();判斷當前是走新的api還是舊的api
connect(); 實例化cluster (明確mr運行在本地還是yarn)
submitJobInternal 真正提交任務的方法
checkSpecs(job);
checkOutputSpecs:檢查輸出路徑是否存在和有沒有設置
submitClient.getNewJobID():獲取jobid
writeSplits:切片分割數據的方法
writeConf(conf, submitJobFile):將切片信息和配置文件寫入到臨時目錄
status = submitClient.submitJob(jobId, submitJobDir.toString() 提交job任務,返回提交狀態
state = JobState.RUNNING提交任務完成后將DEFINE改為RUNNING
isSuccessful() 判斷任務執行成功還是失敗
return status.getState() == JobStatus.State.SUCCEEDED;
9、處理數據時怎么完成切片的
inpt -> inputFormat -> map ->shuffle -> reduce -> outputformat -> 本地文件
默認私用的是TextInputFormat
getSplits():切片方法
isSplitable(job, path):判斷文件是否支持切片,根據文件路徑獲取壓縮格式,如果支持切片返回true,如果文件不是壓縮文件,則直接返回true
file.getBlockSize();獲取塊大小
Math.max(minSize, Math.min(maxSize, blockSize)):獲取切片的大小
當需要讓切片的大小小於塊大小的時,要調整maxsize
當需要讓切片的大小大於塊大小的時,要調整minsize
默認的切片大小時128M
long bytesRemaining = length;
while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
splits.add(makeSplit(path, length-bytesRemaining, splitSize,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
bytesRemaining -= splitSize;
}
10、IntFormat
inputFormat:把文件內容轉換成key,value值
默認使用的是TextInputFormat
InputFormat<?, ?> input =
ReflectionUtils.newInstance(job.getInputFormatClass(), conf);
TextInputFormat extends FileInputFormat<LongWritable, Text>
TextInputFormat:沒有重寫切片方法getSplits,默認使用的時FileInputFormat的切片方法
返回:LineRecordReader -> LongWritable, Text
NLineInputFormat: NLineInputFormat extends FileInputFormat<LongWritable, Text>
NLineInputFormat:重寫了getSplits方法,默認按照行進行切片
返回:LineRecordReader -> LongWritable, Text
CombineFileInputFormat: CombineFileInputFormat<K, V> extends FileInputFormat
CombineTextInputFormat extends CombineFileInputFormat<LongWritable,Text>
CombineFileInputFormat:重寫了getSplits方法,自定義切片的大小
返回的是:CombineFileRecordReader ->LongWritable,Text
KeyValueTextInputFormat:KeyValueTextInputFormat extends FileInputFormat<Text, Text>
KeyValueTextInputFormat:沒有重寫切片方法getSplits,默認使用的時FileInputFormat的切片方法
返回的是:KeyValueLineRecordReader -> Text, Text
SequenceFileInputFormat<K, V> extends FileInputFormat<K, V>
SequenceFileInputFormat:沒有重寫切片方法getSplits,默認使用的時FileInputFormat的切片方法
返回的是:SequenceFileRecordReader -> Text, Text
11、壓縮
hadoop種的壓縮方式有哪些?哪些方式壓縮文件支持切片?mr可以在哪些位置執行壓縮?
壓縮的作用(優點)和原則是什么?默認是否開啟了壓縮,怎么開啟map、reduce端的壓縮功能?
(1) DEFLATE、Gzip、bzip2(支持切片)、LZO(支持切片)、Snappy
(2) 可以在mapreduce執行任務前(數據輸入前的數據壓縮)、任務中(map到reduce的數據傳輸過程中的數據壓縮)、任務后(執行完畢后的數據壓縮)
(3)壓縮會占用一定的CPU資源,合理采用壓縮可以減少磁盤io和網絡數據傳輸,提高mr的整體運行效率原則:運算密集型任務少用壓縮,IO密集型任務多使用壓縮
(4)mr默認沒有開啟壓縮功能
// 開啟map端輸出壓縮
configuration.setBoolean("mapreduce.map.output.compress", true);
// 設置map端輸出壓縮方式
configuration.setClass("mapreduce.map.output.compress.codec", BZip2Codec.class, CompressionCodec.class);
//設置reduce端輸出壓縮開啟
FileOutputFormat.setCompressOutput(job, true);
// 設置壓縮的方式
FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class);
