一 Combiner组件意义
有一个文件,总共620M, 有5个数据块,每一个数据块有三个副本,
比如如上图所示,有5台机器,那这文件的数据块分布如图示:
按照InputSplit,那有可能就是5个map任务,而且这5个Map任务很有可能2个或者3个分配同一台机机器运行,这取决于YARN中ContainerAllocator如何分配资源的问题,所以这一台机器可能需要溢写溢写数据到磁盘,每一map任务估计要溢写(128-100*80%)= 48M
那么就有可能溢写很多文件出来;又或者是我们调大了splitSize大小,比如256M,那么我们单个任务需要溢写大小(256-100*80%)=176M
所以Map任务就有可能多出很多输出结果,会有什么问题呢?
Reduce会到对应的节点拷贝map输出结果,如果结果太多,那么势必网络带宽占用的很严重,降低了程序的性能。
有的输出结果其实我们是可以在reduce之前再同一台机器进行一次聚合,这样reduce来拷贝map结果的时候,就可以减少网络I/O,
这个操作就是Combiner。
总之一句话:map输出很多的时候,可以现根据key进行一次聚合操作,从而减少reduce 从map端copy数据带来的网络I/O。本质上就是一个map端的reducer
二 Combiner触发时机
时机一:
在我们spill的过程中, 如果设置combiner就会在排序的结果上调用combiner,当然不是什么时候都适合设置Combiner,如果一个分区的数据(key-value)很少,我们不适合去设置Combiner。这个也就是我们以前所说的分组。
时机二:
在map任务可能有很多输出,会溢写很多个文件到磁盘,在map任务结束前,会根据情况合并到一个大的分区,对应的索引文件也会合并。
在这个时候如果我们设置了Combiner,且spill生成的文件数也就是我们对应分区数或者叫numSplil> 我们配置的mapreduce.map.combi
ner.minSpills,在合并之前会再次运行Combiner。 如果spill文件数量太少,没有达到这个值,那么运行Combiner是不划算的,所以则不会调用Combiner。即使我们设置了,也不会调用.
三 是否任意情况下都适合使用Combiner
3.1如果map任务输出很少,就没有必要进行Combiner
3.2Combiner针对汇总统计比较实用,因为Combiner的输出,其实也是Reducer的输入,所以Combiner的出现不应该导致结果不正确
四 代码实现Combiner
public static class IntSumCombinerextends Reducer<Text, IntWritable, Text,IntWritable> {
private IntWritable result = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values,
Reducer<Text,IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
if (values == null) {
return;
}
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
result.set(sum);
context.write(key, result);
}
}