hadoop 分片机制

  1.  hadoop mr 的map端输入默认切片算法:

首先明确几个概念:

最小切片大小: minSplitSize=1

最大切片大小: maxSplitSize=Long.MAX

块大小:blockSize

切片的大小范围值:minSize=max(1,minSplitSize)

                                maxSize=maxSplitSize

  • split大小由minSize、minSize、blocksize决定,以下是默认配置情况下的
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
 
  protected long getFormatMinSplitSize() {
    return 1;
  }
  
   public static long getMinSplitSize(JobContext job) {
   // SPLIT_MINSIZE默认值为0,因此getMinSplitSize(JobContext job)返回值为1
    return job.getConfiguration().getLong(SPLIT_MINSIZE, 1L);
  }
  • long maxSize = MAX_VALUE
    long maxSize = getMaxSplitSize(job);
	
	// 返回默认值MAX_VALUE
    public static long getMaxSplitSize(JobContext context) {
    return context.getConfiguration().getLong(SPLIT_MAXSIZE, 
                                              Long.MAX_VALUE);
  }
  
  // 获取配置文件参数值
  public long getLong(String name, long defaultValue) {
  // 用户为自定义参数属性
    String valueString = getTrimmed(name);
    if (valueString == null)
	// 返回系统默认值,即public static final long MAX_VALUE
      return defaultValue;
    String hexString = getHexDigits(valueString);
    if (hexString != null) {
      return Long.parseLong(hexString, 16);
    }
    return Long.parseLong(valueString);
  }
  • blocksize = 134217728

由上面三个参数就可以计算出分片大小了,也能得到如下结论:

Split与block的对应关系可能是多对一,默认是一对一
在mapreduce的FileInputFormat类中的getSplits() 方法对文件进行split,算法如下:

Math.max(minSize,Math.min(maxSize, blockSize)),其中maxSize是取得longValueMax的值

1.如果blockSize小于maxSize && blockSize 大于 minSize之间,那么split就是blockSize(一对一);

2.如果blockSize小于maxSize && blockSize 小于 minSize之间,那么split就是minSize;

3.如果blockSize大于maxSize && maxSize   大于 minSize之间,那么split就是maxSize(多对一);

4.如果blockSize大于maxSize && maxSize   小于 minSize之间,那么split就是maxSize(不存在这种关系)。

在优化过程中,若想调整split大小控制map task的数量,原则如下:
文件大小不变,minsize大小默认,增加map task数量,减小maxSize,则split减小

文件大小不变,maxSize大小默认,减小map task数量,增大minSize,则split增大

注意:split大小如何调整,split只能是一个文件的分片,不能让多个小文件“划入”一个split中

 

分装切片对象的主要源码

文件的最后一个分片可能会超过128MB,由于常量SPLIT_SLOP = 1.1决定,大小范围在:0MB < lastSplit < 128+12.8 MB

 

/** 
   * 生成切片对象集合,InputSplit对象封装.
   * @param job the job context
   * @throws IOException
   */
 
  public List<InputSplit> getSplits(JobContext job) throws IOException {
    StopWatch sw = new StopWatch().start();
	// 分片最小值,getFormatMinSplitSize()返回值为1,getMinSplitSize(job)返回值为1
    long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
	// 分片最大值是常量:public static final long MAX_VALUE
    long maxSize = getMaxSplitSize(job);
 
    // 生成分片列表
    List<InputSplit> splits = new ArrayList<InputSplit>();
	// 判断文件是否可用
    List<FileStatus> files = listStatus(job);
	// 获取文件路径、大小
    for (FileStatus file: files) {
      Path path = file.getPath();
      long length = file.getLen();
      if (length != 0) {
        BlockLocation[] blkLocations;
		// 获取block位置信息
        if (file instanceof LocatedFileStatus) {
          blkLocations = ((LocatedFileStatus) file).getBlockLocations();
        } else {
          FileSystem fs = path.getFileSystem(job.getConfiguration());
          blkLocations = fs.getFileBlockLocations(file, 0, length);
        }
		// 判断文件是否可切片
        if (isSplitable(job, path)) {
		// 获取block大小,默认128MB
          long blockSize = file.getBlockSize();
		  // 计算split大小,默认128MB
          long splitSize = computeSplitSize(blockSize, minSize, maxSize);
			// 文件大小
          long bytesRemaining = length;
		  // 当文件大小满足bytesRemaining/128 > 1.1 进行切片
		  // private static final double SPLIT_SLOP = 1.1;
          while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
			// 记录block索引位置
            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
            splits.add(makeSplit(path, length-bytesRemaining, splitSize,
                        blkLocations[blkIndex].getHosts(),
                        blkLocations[blkIndex].getCachedHosts()));
			// 文件剩余大小
            bytesRemaining -= splitSize;
          }
			// 判断文件是否切片完成
          if (bytesRemaining != 0) {
            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
            splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,
                       blkLocations[blkIndex].getHosts(),
                       blkLocations[blkIndex].getCachedHosts()));
          }
        } else { // not splitable
          splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),
                      blkLocations[0].getCachedHosts()));
        }
      } else { // 文件大小不满足切片要求
        //Create empty hosts array for zero length files
        splits.add(makeSplit(path, 0, length, new String[0]));
      }
    }
    // Save the number of input files for metrics/loadgen
    job.getConfiguration().setLong(NUM_INPUT_FILES, files.size());
    sw.stop();
    if (LOG.isDebugEnabled()) {
      LOG.debug("Total # of splits generated by getSplits: " + splits.size()
          + ", TimeTaken: " + sw.now(TimeUnit.MILLISECONDS));
    }
    return splits;
  }
 
 
	// 计算实际分片大小
  protected long computeSplitSize(long blockSize, long minSize,
                                  long maxSize) {
    return Math.max(minSize, Math.min(maxSize, blockSize));
  }
 
   // 封装分片信息,文件路径,开始位置,文件大小,主机名,存储该block的所有主机名列表
  protected FileSplit makeSplit(Path file, long start, long length, String[] hosts, 
								String[] inMemoryHosts) {
    return new FileSplit(file, start, length, hosts, inMemoryHosts);
  }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值