MapReduce的计算模型
- 在Hadoop中,每个MapReduce任务都被初始化为一个Job。负责控制和调度是JobTracker,一个hadoop集群只有一个JobTracker。负责运行是Tasktracker。
- 一般由hadoop的InputFromat的对应数据子类来将数据转化为Map函数的输入<k1,v1>,Map函数将<k1,v1>转化为Reduce函数输入<k2,v2>,Reduce函数将<k2,v2>转化为<k3,v3>,再通过hadoop的OutputFromat对应数据子类转化为输出数据类型。其中要注意的是当有几个Reduce函数就有几个输出<k3,v3>数据。而没有写Reduce函数时会将Map函数的输出值当做输出数据。
MapReduce任务优化方向
- 任务调度:计算方面hadoop会优先将任务发给空闲的机器。I/O方面Hadoop会尽量将Map任务分配给InputSplit(将文件分片是记录分片长度和位置的数组)所在的机器减少I/O流消耗。
- 数据预处理和InputSplit的大小:由于MapReduce任务擅长少量大数据不擅长大量小数据,所以可以用InputSplit的分片大小和预先将数据合并来控制。一般一个Map任务运行时间在一分钟左右合适。
- Map和Reduce任务的数量:Map任务的数量参考其运行时间,Reduce任务数量和集群的总Reduce数量有关,Reduce数量是总Reduce数量的0.95倍时,hadoop可以快速找到一台空闲的机器执行该任务。Reduce数量是总Reduce数量的1.75倍时,hadoop会使执行速度快的机器分配更多的Reduce任务。
- Combine函数:Map函数产生的中间数据可以通过该函数合并,减少传入Reduce函数的输入信息。
- 压缩:对于Map函数的中间数据压缩,减少网络上的数据传输量。
- 自定义comparator:自定义比较器实现二进制之间的比较,减少序列化和反序列化操作。
总之从几个常见的方面入手:变小文件为大文件,减少Map的数量;压缩最终的输出数据或Map的中间输出结果;在Hadoop安装路径下的conf目录下修改属性,使能够同时运行的Map和Reduce任务数增多,从而提高性能。
MapReduce 的HelloWorld代码
import java.io.IOException;
import java.util.*;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.*;
import org.apache.hadoop.mapreduce.lib.output.*;
import org.apache.hadoop.util.*;
public class WordCount extends Configured implements Tool{
// Map函数
public static class Map extends Mapper<LongWritable, Text, Text, IntWritable>{
private final static IntWritable one=new IntWritable(1);
private Text word=new Text();
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{
String line=value.toString();
StringTokenizer tokenizer=new StringTokenizer(line);
while(tokenizer.hasMoreTokens()){
word.set(tokenizer.nextToken());
context.write(word, one);
}
}
}
// Reduce函数
public static class Reduce extends Reducer<Text, IntWritable, Tex