mapreduce之mapper、reducer个数

这里写图片描述

这个图大概可以描述mapreduce计算模型的执行过程,下面我们就围绕这个图聊几个问题,其中有工作中非常有用的问题:

1. mapper的个数
结论:mapper的个数是由输入数据的大小决定的,一般不需要我们去设置,如果你想控制mapper的个数,那么需要先了解hadoop是怎么控制mapper的个数。
如图所示,每个Mapper Tasker对应一个split(切片),要处理的file被FileInputFormat分成了几个切片就会有几个mapper;FileInputFormat怎么获取的切面呢,直接上源码:

public List<InputSplit> getSplits(JobContext job)  {
    long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
    long maxSize = getMaxSplitSize(job);
    long splitSize = computeSplitSize(blockSize, minSize, maxSize);
    long blockSize = file.getBlockSize();
    long splitSize=computeSplitSize(blockSize,minSize, maxSize);

    }
  protected long getFormatMinSplitSize() {
    return 1;
  }
  public static long getMinSplitSize(JobContext job) {
    return job.getConfiguration().getLong(SPLIT_MINSIZE, 1L);
  }
  public static final String SPLIT_MINSIZE = 
    "mapreduce.input.fileinputformat.split.minsize";
 public static long getMaxSplitSize(JobContext context) {
    return context.getConfiguration().getLong(SPLIT_MAXSIZE, Long.MAX_VALUE);
  }
 public static final String SPLIT_MAXSIZE = 
    "mapreduce.input.fileinputformat.split.maxsize";

 protected long computeSplitSize(long blockSize, long minSize,long maxSize) {
    return Math.max(minSize, Math.min(maxSize, blockSize));
  }

通过源码得出切片数splitSize由三个元素决定:

  1. blockSize block大小,hadoop1默认64M,hadoop2默认128M
  2. minSize 最小值,默认是 1,我可以通过FileInputFormat.setMinInputSplitSize(job, size)方法来修改最小值;
  3. maxSize 最大值,默认是MAX_VALUE = 0x7fffffffffffffffL,可以通过FileInputFormat.setMaxInputSplitSize(job, size)修改最大值
    最后做计算:Math.max(minSize, Math.min(maxSize, blockSize))
    默认情况下:Math.max(1, Math.min(0x7fffffffffffffffL, 128))显然结果为128,也就是说默认情况下有几个block就有几个切片,这也是为了提高mapreduce的运行效率。

2.reducer个数
结论:reducer个数是由partition个数决定。
mapper产生的中间数据经过shuffer过程,根据我们的业务把数据分成若干partition,每个partition的数据由对应的一个reducer来处理。mapreduce决定partition的是:Partitioner类中的intgetPartition(KEY key, VALUE value, int numPartitions)方法,我们来看下默认的分区方法:

public class HashPartitioner<K, V> extends Partitioner<K, V> {

  /** Use {@link Object#hashCode()} to partition. */
  public int getPartition(K key, V value,
                          int numReduceTasks) {
    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
  }

}

由代码看出默认的分区有两个元素决定:

  • key的hash值
  • numReduceTasks,需要我们通过job.setNumReduceTasks(reduceNum) 方法来设置的reducer个数
    最终得出partition个数就是我们设置的个数,比如我们设置job.setNumReduceTasks(3) hashcode除以10的余数就是0、1、2三个值,默认之所以用key的hash值是为了把数据均匀的分布到reducer防止数据倾斜。
    当然了我们可以根据我们自己的业务来继承Partition类重写getPartition方法来决定partition数。
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值