CombineTextInputFormat小文件处理场景

存在的问题

HDFS设计是用来存储海量数据的,特别适合存储TB、PB量级别的数据。但是随着时间的推移,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.55M,2.55M

3.4M

3.4M,3.4M

 

(2)切片过程

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

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

最终会形成3个切片:

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

 

代码举例:

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

 



转载于:https://www.cnblogs.com/TiePiHeTao/p/68fafedf8e1e410015117d1d7104986f.html

### HDFS小文件处理方法与优化方案 #### 存储层面上的小文件优化 为了减少NameNode的压力以及提升存储效率,可以通过以下方式进行优化。在数据采集阶段,可以考虑将多个小文件合并成较大的文件后再上传至HDFS[^1]。这种方式能够有效降低NameNode中元数据的数量,从而节省内存资源。 另一种常见的做法是在HDFS上运行MapReduce程序来实现小文件的合并操作。通过这种方法可以在不改变现有业务逻辑的情况下完成对已有小文件的整理工作。 #### 执行过程中的性能改进措施 当面对大量的小文件时,如果直接使用普通的`TextInputFormat`作为输入格式,则可能会导致过多的任务被创建出来,进而增加系统的负担。因此建议改用`CombineTextInputFormat`类来进行读取操作。该类允许单个Mapper任务处理来自不同路径下的若干个小文件的内容,这样就可以显著减少总的Mapper数目并改善整体作业的表现效果。 另外需要注意的是,由于每一个独立存在的小文件通常会被分配给单独的一个map task去负责解析运算,而这些额外产生的task不仅消耗更多的CPU周期还会占用更多宝贵的集群RAM空间;所以应该尽量避免让系统处于这种高负载状态之中[^2]。 ```python from pyspark import SparkConf, SparkContext conf = SparkConf().setAppName("combine_text_input_format_example") sc = SparkContext(conf=conf) # 使用 CombineTextInputFormat 来加载数据 input_data = sc.newAPIHadoopFile( path="hdfs://path/to/small/files", inputformatClass="org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat", keyClass="org.apache.hadoop.io.LongWritable", valueClass="org.apache.hadoop.io.Text" ) result = input_data.collect() for record in result: print(record) ``` 上述代码片段展示了如何利用PySpark框架配合`newAPIHadoopFile()`函数指定自定义InputFormat为`CombineTextInputFormat`以达到合并小文件的目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值