MR 之 Combiner
背景:
MR的map将数据处理成一个<key,value>键值对,在网络节点间进行整理(shuffle),然后使用Reducer处理数据并进行最终输出。 在上述过程中,我们看到至少两个性能瓶颈:(引用)
思考:
如果我们有10亿个数据,Mapper会生成10亿个键值对在网络间进行传输,但如果我们只是对数据求最大/最小值/求和等,那么很明显,Mapper只需要输出对应的值即可。这样做不仅可以减轻网络压力,同样也可以大幅度提高程序效率。
目标:
Mapreduce中的Combiner就是为了避免map任务和reduce任务之间的数据传输而设置的,Hadoop允许用户针对map task的输出指定一个合并函数。即为了减少传输到Reduce中的数据量。它主要是为了削减Mapper的输出从而减少网络带宽和Reducer之上的负载。
MapReduce中Combiner的作用和用法
集群上的可用带宽限制了MapReduce的作业数量,因此要尽量避免map 和reduce任务之间的数据传输。Hadoop允许针对Mapper任务的输出指定一个Combiner,此Combiner的输出即为reduce的输入 。对map使用Combiner需要注意以下几点:
① Combiner属于MR的优化方案,使用时不能影响不使用时的reduce结果输出;因此Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大/小值等
② Combiner的作用是在对map端有大量输出时,对输出先做一次合并,以减少传输到reducer的数据量;
③ Combiner最基本是实现本地key的归并,Combiner具有类似本地的reduce功能;
④ Combiner的适用的条件是你可以任意的改变值的顺序,并且可以随意的将计算进行分组,同时需要注意的是一个combiner函数只对一个map函数有作用
⑤ Combiner,在Mapper之后Reducer之前运行。Combiner是可选操作,并非每个MR程序都需要
⑥ 与mapper与reducer不同的是,combiner没有默认的实现,需要显式的设置在conf中才有作用。Combiner的实现一般继承Reducer。
以下用一个简单的例子作说明:
数据样本
2013 1 3 7 9
2013 5 4 8 7
2014 5 6 7 5
2014 8 7 7 5
2015 9 5 4 7
2015 4 3 2 5
求以上数据的总和,我们可以用Combiner对每个map中出来的数据进行累加处理,在输出到reduce中。
Combiner如下:
public static class StatisticCombiner extends Reducer<Text, IntWritable, Text, IntWritable> { @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int total = 0; for (IntWritable value : values) { total += value.get(); } context.write(key, new IntWritable(total)); } }
指定Combiner
job.setCombinerClass(StatisticCombiner.class);