【Hadoop】MapReduce使用combiner优化性能

当MapReduce模型中,reduce执行的任务为统计分类类型的值总量或去重后的数量,或最大值最小值时,可以考虑在Map输出后进行combine操作;这样可以减少网络传输带来的开销,同时减轻了reduce任务的负担。
Combine操作是运行在每个节点上的,只会影响本地Map的输出结果;Combine的输入为本地map的输出结果(一般是数据在溢出到磁盘之前,可以减少IO开销),其输出则作为reduce的输入。
很多时候combine的逻辑和reduce的逻辑是相同的,因此两者可以共用Reducer体;这个时候只需要在客户端中设置Map类之后,Reduce类之前加入一行代码: job.setCombinerClass(MyReducer.class);。如果需要自定义combiner类,可以类似这样(示例为从HBase表读取数据,计算,然后写入另一个HBase表中):
public class Test {		
	public static class MyMapper extends TableMapper<ImmutableBytesWritable, ImmutableBytesWritable> {
		@Override
		public void map(ImmutableBytesWritable ibw, Result result, Context context) throws IOException, InterruptedException {
			// 从HBase中读取数据后,进行map相关操作
			// ...
			// 将map结果输出到缓冲区
			context.write(new ImmutableBytesWritable(myMapKey, new ImmutableBytesWritable(myMapValue));
		}
	}
	
	public static class MyCombiner extends TableReducer<ImmutableBytesWritable, ImmutableBytesWritable, ImmutableBytesWritable>{
		@Override
		public void reduce(ImmutableBytesWritable mapKey, Iterable<ImmutableBytesWritable> mapValues, Context context) throws IOException, InterruptedException {
			// 一些操作,如distinct, sum, max, distinct 
			// ...
			// 将combine结果输出到缓冲区
			context.write(mapKey, new ImmutableBytesWritable(combineValue));	
		}
	}	

	public static class MyReducer extends TableReducer<ImmutableBytesWritable, ImmutableBytesWritable, ImmutableBytesWritable> {
		@Override
		public void reduce(ImmutableBytesWritable reduceKeyIBW, Iterable<ImmutableBytesWritable> reduceValues, Context context) throws IOException, InterruptedException {
			// 一些操作,如distinct, sum, max, distinct 
			// ...
			// 将reduce结果(类型Put)输出到缓冲区,用于插入到指定HBase表中
			context.write(null, put);		
		}
	}	

	public static void main(String[] args) throws Exception {
		Configuration configuration = HBaseConfiguration.create();
		Job job = new Job(configuration, "test_mr");
		job.setJarByClass(Test.class);			
		job.setNumReduceTasks(4);  // reduce任务数量默认为1
		
		Scan scan = new Scan();
		scan.setCacheBlocks(false); 
		scan.setCaching(1000); //每次从服务器端读取的行数,默认为配置文件中设置的值
		TableMapReduceUtil.initTableMapperJob("table_for_read", scan, MyMapper.class, ImmutableBytesWritable.class, ImmutableBytesWritable.class, job);
		job.setCombinerClass(MyCombiner.class);   // 设置combiner
		TableMapReduceUtil.initTableReducerJob("table_to_write", MyReducer.class, job);
		
		job.waitForCompletion(true);
	}
}


当combine操作适用而且Map的输出结果数量很大时,combine的作用是很明显的。
以下是某次测试环境中使用combine前后的对比效果,可以看到Combine output records接近 Combine input records的三分之一, 而reduce的输入规模接近原来的十分之一。
两次实际的测试用时分别为50mins16sec, 30mins6sec,耗时节省了接近一半。如图所示:

【Hadoop】MapReduce使用combiner优化性能_第1张图片

【Hadoop】MapReduce使用combiner优化性能_第2张图片



你可能感兴趣的:(【Hadoop】MapReduce使用combiner优化性能)