CombineTextInputFormat小文件处理场景

存在的问题

HDFS设计是用来存储海量数据的,特别适合存储TBPB量级别的数据。但是随着时间的推移,HDFS上可能会存在大量的小文件,这里说的小文件指的是文件大小远远小于一个HDFS块(128MB)的大小HDFS上存在大量的小文件至少会产生以下影响:

消耗NameNode大量的内存

延长MapReduce作业的总运行时间

因为MapReduce框架默认的 TextInputFormat 切片机制是对任务按文件规划切片,如果有大量小文件,就会产生大量的 MapTask,处理小文件效率非常低

解决方案

Hadoop内置提供了一个CombineTextInputFormat类来专门处理小文件,其核心思想是:根据一定的规则,HDFS上多个小文件合并到一个 InputSplit中,然后会启用一个Map来处理这里面的文件,以此减少MR整体作业的运行时间

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

切片机制过程

CombineTextInputForma切片机制过包括:虚拟存储过程切片过程二部分

假设 setMaxInputSplitSize 值为 4M,有如下四个文件

a.txt 1.7M

b.txt 5.1M

c.txt 3.4M

d.txt 6.8M

1虚拟存储过程

1.1)将输入目录下所有文件大小,依次和设置的 setMaxInputSplitSize 值比较,如果不大于设置的最大值,逻辑上划分一个块。

1.2)如果输入文件大于设置的最大值且大于两倍,那么以最大值切割一块,当剩余数据大小超过设置的最大值且不大于最大值2倍,此时将文件均分成2个虚拟存储块(防止出现太小切片)。

1.7M < 4M 划分一块

5.1M > 4M 但是小于 2*4M 划分二块:块1=2.55M,块2=2.55M

3.4M < 4M 划分一块

6.8M > 4M 但是小于 2*4M 划分二块:块1=3.4M,块2=3.4M

最终存储的文件:

1.7M

2.55M2.55M

3.4M

3.4M3.4M

 

2切片过程

2.1)判断虚拟存储的文件大小是否大于 setMaxIputSplitSize 值,大于等于则单独形成一个切片。

2.2)如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。

最终会形成3个切片:

1.7+2.55M,(2.55+3.4M,(3.4+3.4M

 

代码举例:

main方法中:

        job.setInputFormatClass(CombineTextInputFormat.class);
        CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
 
 
 
2
 
 
 
1
        job.setInputFormatClass(CombineTextInputFormat.class);
2
        CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
 
 

总结:

CombineTextInputFormat 小文件处理场景

  • 默认读取数据机制的弊端
  • 默认TextInputFormat 逐个遍历文件 意味着不管文件多大 至少自己本身都是一个切片
    如果小文件过多 势必会形成很多个切片 就会启动多个maptask 浪费资源。
  • CombineTextInputFormat
    • 设置一个切片的最大值 
    • CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
    • 首先,虚拟存储过程


    • 遍历每一个小文件 跟设置值进行比较
      如果小于 自己本身就是一个
      如果大于 不超过2倍 就把该文件平均
      如果大于 超过2倍 就按照最大值切
    • 然后,切片规划的过程
    • 上一步虚拟存储的结果 逐个判断 如果不超过设置的值 就和后面的合并 合并之后如果依然没超过,继续合并 直到超过设置最大值。形成切片。
    • 针对小文件 ,最佳的处理方式 还是上传hdfs之前进行合并,目标--->block size



猜你喜欢

转载自www.cnblogs.com/TiePiHeTao/p/68fafedf8e1e410015117d1d7104986f.html