简单解析mapreduce切片

    在mapreduce中的切片是什么意思?顾名思义就是将数据进行切分,切分为数据片,其实这个切片关乎于map阶段的map个数,以及每个map处理的数据量的大小。

    mapreduce,一个jobmap个数每个map处理的数据量是如何决定的呢另外每个map又是如何读取输入文件的内容呢用户是否可以自己决定输入方式决定map个数呢? 这篇博文就是回答这几个问题的。

    mapreduce作业会根据输入目录产生多个map任务通过多个map任务并行执行来提高作业运行速度但如果map数量过少并行量低作业执行慢如果map数过多资源有限,也会增加调度开销因此根据输入产生合理的map为每个map分配合适的数据量能有效的提升资源利用率并使作业运行速度加快

    mapreduce每个作业都会通过 InputFormat来决定map数量,

InputFormat是一个接口, 提供两个方法:

InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;

RecordReader<K, V> getRecordReader(InputSplit split,JobConf job,Reporter reporter) throws IOException;

    其中getSplits方法会根据输入目录产生InputSplit数组每个InputSplit会相应产生一个map任务, map的输入定义在InputSplit. getRecordReader方法返回一个RecordReader对象, RecordReader决定了map任务如何读取输入数据例如一行一行的读取还是一个字节一个字节的读取等等而我们大多数其实在使用TextInputFormat,但TextInputFormat没有实现自己的getSplits方法继承于FileInputFormat, 因此使用了FileInputFormat的getSplits方法.

    旧接口FileInputFormatgetSplits流程包含两个参数和一个公式:
    mapred.min.split.size        (一个map最小输入长度)

    mapred.map.tasks                (推荐map数量)
    Math.max(minSize, Math.min(goalSize, blockSize))

    

如何决定每个map输入长度呢首先获取输入目录下所有文件的长度和除以mapred.map.tasks(这个属性是我们可以再程序中设置的)得到一个推荐长度goalSize, 然后通过公式: Math.max(minSize, Math.min(goalSize, blockSize))决定map输入长度。 这里的minSizemapred.min.split.size, 这个属性是我们在配置文件中配置的,blockSize为相应文件的block长度这公式能保证一个map的输入至少大于mapred.min.split.size, 对于推荐的map长度,只有它的长度小于blockSize且大于mapred.min.split.size才会有效果由于mapred.min.split.size默认长度为1, 因此通常情况下只要小于blockSize就有效果,否则使用blockSize做为map输入长度.
    因此如果想增加map可以把mapred.min.split.size调小(其实默认值即可), 另外还需要把mapred.map.tasks设置大.如果需要减少map,可以把mapred.min.split.size调大另外把mapred.map.tasks调小.
    这里要特别指出的是FileInputFormat会让每个输入文件至少产生一个map任务因此如果你的输入目录下有许多文件而每个文件都很小例如几十kb, 那么每个文件都产生一个map会增加调度开销作业变慢.
    那么如何防止这种问题呢CombineFileInputFormat能有效的减少map数量。

Hadoop 0.20开始定义了一套新的mapreduce编程接口使用新的FileInputFormat, 它与旧接口下的FileInputFormat主要区别在于它不再使用mapred.map.tasks, 而使用mapred.max.split.size参数代替goalSize, 通过Math.max(minSize, Math.min(maxSize, blockSize))决定map输入长度一个map的输入要大于minSize,小于Math.min(maxSize, blockSize)。
    若需增加map,可以把mapred.min.split.size调小,mapred.max.split.size调大。 若需减少map, 可以把mapred.min.split.size调大并把mapred.max.split.size调小

CombineFileInputFormat

顾名思义, CombineFileInputFormat的作用是把许多文件合并作为一个map的输入.

在它之前,可以使用MultiFileInputFormat,不过其功能太简单以文件为单位,一个文件至多分给一个map处理如果某个目录下有许多小文件另外还有一个超大文件处理大文件的map会严重偏慢.

CombineFileInputFormat是一个被推荐使用的InputFormat. 它有三个配置:

mapred.min.split.size.per.node 一个节点上split的至少的大小
      mapred.min.split.size.per.rack   一个交换机下split至少的大小
      mapred.max.split.size             一个split最大的大小

它的主要思路是把输入目录下的大文件分成多个map的输入并合并小文件做为一个map的输入具体的原理是下述三步:

1.根据输入目录下的每个文件,如果其长度超过mapred.max.split.size,block为单位分成多个split(一个split是一个map的输入),每个split的长度都大于mapred.max.split.size, 因为以block为单位因此也会大于blockSize, 此文件剩下的长度如果大于mapred.min.split.size.per.node, 则生成一个split, 否则先暂时保留.

2. 现在剩下的都是一些长度效短的碎片,把每个rack下碎片合并只要长度超过mapred.max.split.size就合并成一个split, 最后如果剩下的碎片比mapred.min.split.size.per.rack就合并成一个split, 否则暂时保留.

3. 把不同rack下的碎片合并只要长度超过mapred.max.split.size就合并成一个split, 剩下的碎片无论长度合并成一个split.

举例: mapred.max.split.size=1000

     mapred.min.split.size.per.node=300

      mapred.min.split.size.per.rack=100

输入目录下五个文件,rack1下三个文件,长度为2050,1499,10, rack2下两个文件,长度为1010,80. 另外blockSize500.

经过第一步生成五个split: 1000,1000,1000,499,1000. 剩下的碎片为rack1:50,10; rack210:80

由于两个rack下的碎片和都不超过100, 所以经过第二步, split和碎片都没有变化.

第三步,合并四个碎片成一个split, 长度为150.

 如果要减少map数量可以调大mapred.max.split.size, 否则调小即可.

其特点是一个块至多作为一个map的输入,一个文件可能有多个块,一个文件可能因为块多分给做为不同map的输入, 一个map可能处理多个块,可能处理多个文件。

转载于:https://my.oschina.net/U74F1zkKW/blog/356274

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值