大数据学习之路(15):MapReduce的combiner合并小能手

98 阅读2分钟

一、combiner 合并

1.1 工作位置

如下图回顾,combiner是MapReduce阶段的可选流程。

它的工作位置:

1. kv缓冲区中溢写到磁盘时可以使用combiner (只要设置,无条件使用)
2. 每个mapTask的所有数据从缓冲区写到磁盘后,在进行归并的时候可以使用combiner(满足条件使用,溢写次数>=3)

image.png

1.2 为什么要使用combiner

我们知道,MapReduce 使用Mapper将数据处理成一个个的<k,value> 键值对,在网络节点间对其进行整理(shuffle),然后使用Reduce处理数据并进行最终输出。

image.png

在这个过程中,我们可以看到两个性能瓶颈:

  • 如果我们有1亿个数据,Mapper会生成1亿个键值对在网络间传输,但如果我们只是求累加值,那么明显可以在Mapper阶段完成累加值,然后将得到的值传给reduce,这样就变成一个键值对在网络间传输,可以提高程序效率。 总结: 网络带宽严重被占降低程序效率

  • 太多的键值对最终聚集于一个单一的Reduce之上,从而降低程序的性能。

1.3 combiner概述

为了解决上面的瓶颈,combiner横空出世。它是MpaReduce 中Mapper和Reduce之外的一种组件。目的就是在每个MapTask中将输出的kv提前进行合并,能降低map到Reduce的传输数量及最终reduce处理的数据量。

【注意】:

  • combiner 组件的父类就是Reducer
  • combiner 和Reducer的区别在于运行的位置,combiner是在每一个MapTask所在的节点运行,而Reducer是接收全局所有的Mapper的输出结果。
  • combiner能够应用的前提是不能影响最终的业务逻辑。

1.4 自定义conbiner步骤

(a)自定义一个Combiner继承Reducer,重写Reduce方法

public class WordcountCombiner extends Reducer<Text, IntWritable, Text,IntWritable>{
 
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
 // 1 汇总操作
int count = 0;
for(IntWritable v :values){
count += v.get();
}
 
 
 // 2 写出
context.write(key, new IntWritable(count));
}
}

(b)在job去驱动类中设置:

job.setCombinerClass(WordcountCombiner.class);

二、combiner 合并案例实操

在之前的wordcount案例,新增一个Combiner类继承Reducer

package com.atguigu.mr.combiner;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
 
public class WordcountCombiner extends Reducer<Text, IntWritable, Text, IntWritable>{
 
IntWritable v = new IntWritable();
 
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
 
        // 1 汇总
int sum = 0;
 
for(IntWritable value :values){
sum += value.get();
}
 
v.set(sum);
 
// 2 写出
context.write(key, v);
}
    }

使用前

image.png

使用combiner后:

image.png