MapReduce核心高频面试题
一、ReduceTask工作机制
1、Copy阶段:ReduceTask从各个MapTask上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阈值,则写到磁盘上,否则直接放到内存中。
2、Merge阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
3、Sort阶段:按照MapReduce语义,用户编写reduce()函数输入数据是按key进行聚集的一组数据。为了将key相同的数据聚在一起,Hadoop采用了基于排序的策略。由于各个MapTask已经实现对自己的处理结果进行了局部排序,因此,ReduceTask只需对所有数据进行一次归并排序即可。
4、Reduce阶段:reduce()函数将计算结果写到HDFS上。
二、请描述mapReduce有几种排序及排序发生的阶段?
1、排序的分类
1.1、部分排序
MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部排序。
1.2、全排序
如何用Hadoop产生一个全局排序的文件?最简单的方法是使用一个分区。但该方法在处理大型文件时效率极低,因为一台机器必须处理所有输出文件,从而完全丧失了MapReduce所提供的并行架构。
替代方案:首先创建一系列排好序的文件;其次,串联这些文件;最后,生成一个全局排序的文件。主要思路是使用一个分区来描述输出的全局排序。例如:可以为待分析文件创建3个分区,在第一分区中,记录的单词首字母a-g,第二分区记录单词首字母h-n, 第三分区记录单词首字母o-z。
1.3、辅助排序(GroupingComparator分组)
Mapreduce框架在记录到达reducer之前按键对记录排序,但键所对应的值并没有被排序。甚至在不同的执行轮次中,这些值的排序也不固定,因为它们来自不同的map任务且这些map任务在不同轮次中完成时间各不相同。 一般来说,大多数MapReduce程序会避免让reduce函数依赖于值的排序。但是,有时也需要通过特定的方法对键进行排序和分组等以实现对值的排序。
1.4、二次排序
在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。
2、自定义排序WritableComparable
bean对象实现WritableComparable接口重写compareTo方法,就可以实现排序
代码语言:javascript复制@Override
public int compareTo(FlowBean o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
3、排序发生的阶段
- 一个是在map side发生在spill后partition前。
- 一个是在reduce side发生在copy后 reduce前。
三、请描述mapReduce中shuffle阶段的工作流程,如何优化shuffle阶段?
分区,排序,溢写,拷贝到对应reduce机器上,增加combiner,压缩溢写的文件。
四、请描述mapReduce中combiner的作用是什么,一般使用情景,哪些情况不需要,及和reduce的区别?
1、Combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量。
2、Combiner能够应用的前提是不能影响最终的业务逻辑,而且,Combiner的输出kv应该跟reducer的输入kv类型要对应起来。
3、Combiner和reducer的区别在于运行的位置。
- Combiner是在每一个maptask所在的节点运行;
- Reducer是接收全局所有Mapper的输出结果。
五、如果没有定义partitioner,那数据在被送达reducer前是如何被分区的?
如果没有自定义的 partitioning,则默认的 partition 算法,即根据每一条数据的 key的 hashcode 值摸运算(%)reduce 的数量,得到的数字就是“分区号”。
六、MapReduce怎么实现 TopN?
可以自定义groupingcomparator,或者在map端对数据进行排序;然后再reduce输出时,控制只输出前n个数,就达到了topn输出的目的。
七、有可能使 Hadoop 任务输出到多个目录中么?如果可以,怎么做?
1、可以输出到多个目录中,采用自定义OutputFormat。
2、实现步骤:
- 自定义outputformat
- 改写recordwriter,具体改写输出数据的方法write()
八、简述hadoop实现join的几种方法及每种方法的实现
1、reduce side join
Map端的主要工作:为来自不同表(文件)的key/value对打标签以区别不同来源的记录。然后用连接字段作为key,其余部分和新加的标志作为value,最后进行输出。
Reduce端的主要工作:在reduce端以连接字段作为key的分组已经完成,我们只需要在每一个分组当中将那些来源于不同文件的记录(在map阶段已经打标志)分开,最后进行合并就ok了。
2、map join
在map端缓存多张表,提前处理业务逻辑,这样增加map端业务,减少reduce端数据的压力,尽可能的减少数据倾斜。
具体办法:采用distributedcache
2.1、在mapper的setup阶段,将文件读取到缓存集合中。
2.2、在驱动函数中加载缓存。
代码语言:javascript复制job.addCacheFile(new URI("file:/e:/mapjoincache/pd.txt"));// 缓存普通文件到task运行节点
九、请简述hadoop怎样实现二级排序
对map端输出的key进行排序,实现的compareTo方法。 在compareTo方法中排序的条件有二个。
十、Hadoop中RecordReader的作用是什么?
1、以怎样的方式从分片中读取一条记录,每读取一条记录都会调用RecordReader类;
2、系统默认的RecordReader是LineRecordReader;
3、LineRecordReader是用每行的偏移量作为map的key,每行的内容作为map的value;
4、应用场景:自定义读取每一条记录的方式;自定义读入key的类型,如希望读取的key是文件的路径或名字而不是该行在文件中的偏移量。
十一、给你一个1G的数据文件。分别有id,name,mark,source四个字段,按照mark分组,id排序,手写一个MapReduce?其中有几个Mapper?
1、在map端对mark排序,在reduce端对id分组
代码语言:javascript复制@Override
public int compareTo(GroupBean o) {
int result = this.mark.compareTo(o.mark);
if (result == 0)
return Integer.compare(this.id,o.id);
else
return result;
}
代码语言:javascript复制@Override
public int compare(WritableComparable a, WritableComparable b) {
GroupBean aBean = (GroupBean) a;
GroupBean bBean = (GroupBean) b;
int result;
if (aBean.getMark() > bBean. getMark()) {
result = 1;
} else if (aBean. getMark() < bBean. getMark()) {
result = -1;
} else {
result = 0;
}
return result;
}
2、几个mapper
1024m/128m=8块