Hadoop(十三)MapReduce Combiner 合并

为什么会有Combiner

在WordCount的案例里,我们发现每一个Maptask任务会计算出a:1,2000次,针对像a:1这种完全一样的数据,如果进入到Mapreduce里的话,如果有5个maptask,那么会对5*2000 个a:1进行计算,效率较低。

那么我们是否可以在MaperTask阶段,将2000个a:1 做一次合并形成a:2000,再送入MapReduce里,就变成了5个a:2000大大减轻了计算。这个组件就是Combiner,这样做的好处很明显,就是大大减少了输入到Reduce的数据量,从而减少了reduce处理的资源压力。

    所以对于hadoop自带的wordcount的例子,value就是一个叠加的数字,所以map一结束就可以进行reduce的value叠加,而不必要等到所有的map结束再去进行reduce的value叠加

       因此,我们可以这么说: Combiner就是运行在一个MapTask上的Reducer,即局部汇总,而真正的Reducer是可以面向所有MapTask的。​它是MR里shuffle的一项可选流程,位于Map阶段和Reduce阶段之间,是MR中,除Mapper和Reducer之外的一种组件,但并不是默认存在的组件,其可有也可无。​避免任务在reduceTask上的积压。每一个map都可能会产生大量的本地输出,通过使用Combiner,可以将部分数据的处理工作从Reducer之前转移到Mapper之后,减少了Mapper输出到Reducer之间需要传输的数据量,从而提高了整体的性能。

     另外Combiner是一个本地化的reduce操作,它是map运算的后续操作,主要是在map计算出中间文件前做一个简单的合并重复key值的操作
 

什么情况下不能使用Combiner

另外,在"不能影响最终的业务逻辑"的情况下可以使用这个组件

比如说,当前的业务逻辑是算输入数据的平均值,那我提前对每个MapTask做Combiner,来计算每个MapTask的平均值,然后把结果传给Reducer来计算全部MapTask的平均值,这样子可以吗?

这当然是不行的。

假设两个MapTask,一个接收数字3、5,7,另一个接收数字2和6,分别计算平均值,那就是5和4,再传进Reducer计算平均值:(5+4)/2=4.5。

但是其实(3+5+7+2+6)/5 = 4.6,上面结果算的明显不对。

所以, 是否可以使用Combiner,以及使用什么样的Combiner,都得以不影响最终业务逻辑为前提,不能随便应用。不是所有的计算场景都适合用Combiner,只有操作满足结合律的才可设置Combiner,比如求和,求最值等;而对于求中位数,求平均值等不适合用Combiner。

如何使用 Combiner


Combiner 和 Reducer 一样,编写一个类,然后继承 Reducer,reduce 方法中写具体的 Combiner 逻辑,然后在 job 中设置 Combiner 组

执行后看到map的输出和combine的输入统计是一致的,而combine的输出与reduce的输入统计是一样的。由此可以看出规约操作成功,而且执行在map的最后,reduce之前。

其实Combiner也可以看成就是Reduce,俩者的代码完全一样

自定义Combiner的两种方式还是以WordCount来举例。

我们运行一下wordcount案例,见Hadoop(九)MapReduce 案例2-CSDN博客

hadoop jar /hadoopmapreduce-1.0-SNAPSHOT.jar words.JobMain /wcinput /my_wcoutput1

不加Combiner的情况看一下后台日志

第一个是Mapper的输出
第二个是Combiner的,发现都是0
第三个是Reduce接收的

打印的日志里,有一个Map-Reduce Framework区域,如上图图,红色框出来的部分就是combine的运行结果。

combine input records代表输入到Combiner的数据行数,combine output records则表示经过Combiner处理后,输出的数据行数。

我们来增加Combiner组件

第一种方式,增加一个WordCombiner来继承Reducer:

package combiner;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**

 * @description Reduce 阶段,把 key 相同的数据进行累计,得到每个单词出现的次数
 */
public class WordCombiner extends Reducer<Text, LongWritable,Text,LongWritable> {
    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        //1、定义一个变量
        long count = 0;
        //2、迭代
        for (LongWritable value : values) {
            count += value.get();
        }
        //3、写入上下文
        context.write(key,new LongWritable(count));
    }
}

然后在JobMain驱动类里声明:

// 指定需要使用combiner,以及用哪个类作为combiner的逻辑
job.setCombinerClass(WordCombiner .class);

但是!

实际上如果你看过里的代码,会发现,我们自定义的这个Combiner,里面的reduce()跟我们自定义的WordReducer类的reduce()一模一样,甚至整个类都是一样的,因为所谓的Combiner就是运行在单个MapTask的Reducer,再加上我们的业务要求,处理逻辑自然完全一致。

所以在这种情况下,我们根本不需要再定义一个Combiner类,直接使用自定义Reducer类来声明就可以。

这就是第二种方案,即我们只需要在驱动类里直接这么写:

// 指定需要使用Combiner,以及用哪个类作为Combiner的逻辑
job.setCombinerClass(WordReducer.class);

加上代码以后,我们重新打包运行

hadoop jar /hadoopmapreduce-1.0-SNAPSHOT.jar words.JobMain /wcinput/words.txt /my_wcoutput111

我们看一下启用自定义Combiner后的输出结果。

可以看到,启用前Reduce shuffle bytes是170字节,启用后是106字节,说明数据在传到reduce前经过了自定义Combiner的处理,数据量减小了。所以我们发现第一个是没有任何变化的,第二个不再是0了,而是有了数据,第三的明显比没有加Combiner的少了许多,这就说明Combiner生效了,起到了为Reduce减负的作用

Combiner的作用及工作原理

 1.减少数据传输量:

  Mapper阶段的输出数据可能会非常庞大,如果不经过合并直接传输给Reducer,会造成大量的数据传输开销,降低整个任务的执行效率。Combiner通过在Mapper输出后进行局部合并,可以减少需要传输的数据量,从而提高了效率。

  2.局部聚合:

  Combiner可以对Mapper输出的数据进行局部聚合,将具有相同键的数据合并在一起。例如,在Word Count任务中,Mapper输出的键值对为(word, 1),Combiner可以将相同的word进行合并,并将其对应的计数值累加起来,减少了后续Reducer处理的数据量。

  3.降低网络传输开销:

  由于Combiner可以减少传输的数据量,因此可以降低网络传输的开销。特别是在大规模数据处理任务中,网络传输往往是整个任务的瓶颈之一,通过使用Combiner可以有效地减少网络传输开销,提高整体的性能。

  4.工作原理:

  在MapReduce任务中,Mapper会将输入数据分片处理,并生成键值对作为输出。这些键值对会按照键的排序顺序被分发到Reducer中进行处理。Combiner在这个过程中介入,在Mapper输出后,对输出的键值对进行合并操作。Combiner的工作方式与Reducer类似,它接收Mapper输出的键值对,并根据键进行合并操作。然后,合并后的键值对会被发送到Reducer进行进一步处理。

      在MapReduce任务中,每一个Mapper都可能产生大量的输出到Reducer,这对网络带宽和Reducer负载都有很大的压力,严重时会限制Hadoop集群的计算能力。Combiner(合并)就是为了减少Mapper和Reducer之间的数据传输而生的,添加Combiner绝不能影响最终的计算结果。

MapReduce允许用户针对Mapper阶段的输出进行一次合并,这次合并就是Combiner,主要是为了削减Mapper的输出从而减少网络带宽和Reducer之上的负载。Combiner最基本的功能就是实现本地Key的合并。一般来说,Combiner和Reducer的功能相同,Combiner相当于本地的Reducer,所以常以Reducer来作为Combiner使用。

   在没有加入Combiner之前,Mapper的输出就是Reducer的输入。在Mapper和Reducer之间加入了Combiner之后,Mapper的输出就是Combiner的输入,Combiner的输出就是Reducer的输入。如果加入Combiner是可插拔的,那么该Combiner的输出类型就和Mapper的输出类型一致,该Combiner的输入类型就和Reducer的输入类型一致。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Allen019

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值