hadoop系列十六——MapReduce之Combiner详解(可解决数据倾斜问题)

为什么需要进行Map规约操作

众所周知,Hadoop框架使用Mapper将数据处理成一个个的<key,value>键值对,在网络节点间对其进行整理(shuffle),然后使用Reducer处理数据并进行最终输出。

在上述过程中,我们看到至少两个性能瓶颈:

(1)如果我们有10亿个数据,Mapper会生成10亿个键值对在网络间进行传输,但如果我们只是对数据求最大值,那么很明显的Mapper只需要输出它所知道的最大值即可。这样做不仅可以减轻网络压力,同样也可以大幅度提高程序效率

总结:网络带宽严重被占降低程序效率;

(2)假设使用美国专利数据集中的国家一项来阐述数据倾斜这个定义,这样的数据远远不是一致性的或者说平衡分布的,由于大多数专利的国家都属于美国,这样不仅Mapper中的键值对、中间阶段(shuffle)的键值对等,大多数的键值对最终会聚集于一个单一的Reducer之上,压倒这个Reducer,从而大大降低程序的性能。

初步探索Combiner

在MapReduce编程模型中,在Mapper和Reducer之间有一个非常重要的组件,它解决了上述的性能瓶颈问题,它就是Combiner。每一个map都可能会产生大量的本地输出,Combiner的作用就是对map端的输出先做一次合并,以减少在map和reduce节点之间的数据传输量,以提高网络IO性能,是MapReduce的一种优化手段之一。

  • combiner是MR程序中Mapper和Reducer之外的一种组件

  • combiner组件的父类就是Reducer

  • combiner和reducer的区别在于运行的位置:

  • Combiner是在每一个maptask所在的节点运行

  • Reducer是接收全局所有Mapper的输出结果;

  • combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量

Combiner设置

具体实现步骤:

1.自定义一个combiner继承Reducer,重写reduce方法
2.job中设置: job.setCombinerClass(CustomCombiner.class)

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


PS:

①与mapper和reducer不同的是,combiner没有默认的实现,需要显式的设置在conf中才有作用。

②Combiner的输出是Reducer的输入,如果Combiner是可插拔的,添加Combiner绝不能改变最终的计算结果。所以Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大值等。

案例:数据倾斜场景

数据:

a a a a a a b b b a a a
a a a a c c b c a a a c
a b b c a a d d e e f f
f g a a a b a b h h g j

需求:

需要做wordcount,解决数据倾斜

代码:









//map端

public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
	
	@Override
	protected void map(LongWritable key, Text value, Context context)
			throws IOException, InterruptedException {

		// 切单词
		String line = value.toString();
		String[] words = line.split(" ");
		for(String word:words){
			context.write(new Text(word), new IntWritable(1));
			
		}
	}
}
















//Reducer,同样也可以作为combiner的代码
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
	
	
	@Override
	protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
	
		
		int count = 0;
		
		Iterator<IntWritable> iterator = values.iterator();
		while(iterator.hasNext()){
			
			IntWritable value = iterator.next();
			count += value.get();
		}
		
		
		context.write(key, new IntWritable(count));
		
	}
	
	

}






public class JobSubmitterWindowsLocal {
	
	public static void main(String[] args) throws Exception {
		
		Configuration conf = new Configuration();

		//conf.set("fs.defaultFS", "file:///");
		//conf.set("mapreduce.framework.name", "local");

		Job job = Job.getInstance(conf);
		
		job.setJarByClass(JobSubmitterLinuxToYarn.class);
		
		job.setMapperClass(WordcountMapper.class);
		job.setReducerClass(WordcountReducer.class);
		job.setCombinerClass(WordcountReducer.class)    //设置Combiner
		
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		
		// 设置maptask端的局部聚合逻辑类
		job.setCombinerClass(WordcountReducer.class);
		
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		job.setNumReduceTasks(Integer.parseInt(args[2]));
		
		boolean res = job.waitForCompletion(true);
		System.exit(res?0:1);
		
	}
	



}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值