Hadoop CombineTextInputFormat 切片机制

关于大量小文件的优化策略。

背景

默认情况下 TextInputformat 对任务的切片机制是按文件规划切片,不管文件多小,都会 是一个单独的切片,都会交给一个 maptask,这样如果有大量小文件,就会产生大量的 maptask, 处理效率极其低下。

优化

预处理

最好的办法,在数据处理系统的最前端(预处理/采集),将小文件先合并成大文 件,再上传到 HDFS 做后续分析。

CombineTextInputFormat

如果已经是大量小文件在 HDFS 中了,可以使用另一种 InputFormat 来做切片(CombineTextInputFormat),它的切片逻辑跟 TextFileInputFormat 不同:它可以将 多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个 maptask

优先满足最小切片大小,不超过最大切片大小 。

CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m CombineTextInputFormat.setMinInputSplitSize(job, 2097152);// 2m

举例:0.5m+1m+0.3m+5m=2m + 4.8m=2m + 4m + 0.8m

具体配置

// 如果不设置 InputFormat,它默认用的是 TextInputFormat.class 
job.setInputFormatClass(CombineTextInputFormat.class) 
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m 
CombineTextInputFormat.setMinInputSplitSize(job, 2097152);// 2m

Demo

准备了5个小文件,如下:

☁  CombineTextInputFormat  pwd
/Users/ylj/demo/input/CombineTextInputFormat
☁  CombineTextInputFormat  ll
total 19400
-rw-r--r--  1 ylj  staff   176K  4  7 15:35 flie1.txt
-rw-r--r--  1 ylj  staff   879K  4  7 15:39 flie2.txt
-rw-r--r--  1 ylj  staff   1.1M  4  7 15:39 flie3.txt
-rw-r--r--  1 ylj  staff   2.1M  4  7 15:41 flie4.txt
-rw-r--r--  1 ylj  staff   3.3M  4  7 15:42 flie5.txt

测试默认配置

-w1173

测试CombineTextInputFormat

仅设置setInputFormatClass

//设置InputFormat
job.setInputFormatClass(CombineTextInputFormat.class);

此时

SPLIT_MAXSIZE = Long.MAXValue
SPLIT_MINSIZE = 1

5个文件相加在此区间内,所以number of splits:1

-w1148

设置SPLIT_MAXSIZE、SPLIT_MINSIZE

//设置InputFormat
job.setInputFormatClass(CombineTextInputFormat.class);
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
CombineTextInputFormat.setMinInputSplitSize(job, 2097152);// 2m

此时
CombineTextInputFormat 切片机制

  1. 判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个切片;
  2. 如果不大于则跟下一个存储文件进行合并,共同形成一个切片。

-w1213

源码

文件:/org/apache/hadoop/mapreduce/lib/input/CombineFileInputFormat.java

if (maxSize == 0) {
    myLength = left;
} else {
    if (left > maxSize && left < 2 * maxSize) {
      // if remainder is between max and 2*max - then
      // instead of creating splits of size max, left-max we
      // create splits of size left/2 and left/2. This is
      // a heuristic to avoid creating really really small
      // splits.
      myLength = left / 2;
    } else {
      myLength = Math.min(maxSize, left);
    }
}

猜你喜欢

转载自blog.csdn.net/yljphp/article/details/89070948