最近检查发现生产环境 HDFS 上文件和目录数量已经有 70w+ 个,对 namenode 的压力也越来越大,需要对 HDFS 上的小文件进行合并处理,但并非所有文件都可以合并,一般是针对 Hive 表映射在 HDFS 的文件进行合并来减少文件数量,下面整理出来的 3 个处理方法:

方法一:parquet文件

cdh 默认安装路径:/opt/cloudera/parcels/CDH-6.2.0-1.cdh6.2.0.p0.967373/bin/parquet-tools

参考:使用parquet-tools工具查看parquet文件 - 简书

测试本地合并成功

使用官方工具 parquet-tools 合并指定的 parquet 文件

使用 parquet-tools 对多个 parquet 文件进行合并,使用方法:

# 合并 HDFS 上的 parquet 文件

hadoop jar parquet-tools-1.9.0.jar merge /tmp/a.parquet /tmp/b.parquet

# 合并本地的 parquet 文件

java -jar parquet-tools-1.9.0.jar merge /tmp/a.parquet /tmp/b.parquet

参考文档2中也明确地提到:

we strongly recommend *not* to use parquet-tools merge unless you really know what you’re doing. It is known to cause some pretty bad performance problems in some cases. The problem is that it takes the row groups from the existing file and moves them unmodified into a new file – it does *not* merge the row groups from the different files. This can actually give you the worst of both worlds – you lose parallelism because the files are big, but you have all the performance overhead of processing many small row groups.

因此使用parquet-tools并不可取现在一个矛盾,系统有很多小文件,理想方案控制写入parquet 时控制rowgroup 。

参考网站:[PARQUET-460] Parquet files concat tool - ASF JIRA

                  Parquet文件读写与合并小Parquet文件 - 博客 - 编程圈

方法二:parquet文件-python 方式

python读取hdfs上的parquet文件方式_python_得牛网

方法三:hive 参数方式

Create Table As Select (CTAS),即用 hive 把数据从源表(含大量小文件)查出并插入到一张临时表,所有数据插入到临时表后,源表和临时表的表名互换即可。注意,你需要给 hive 会话添加下面的配置来控制小文件合并的条件:

# 控制每个任务合并小文件后的文件大小(默认256000000,256MB):

set hive.merge.size.per.task=2048000000;

# 告诉 hive 什么样的文件属于小文件(默认16000000,小于16MB):

set hive.merge.smallfiles.avgsize=512000000;

# 是否合并Map的输出文件(默认true):

set hive.merge.mapfiles=true;

# 是否合并Reduce的输出文件(默认false):

set hive.merge.mapredfiles=true;

另外,如果 hive 表是分区表,你可以写脚本每个分区遍历合并,但是每个分区合并都需要提交一个 mr job 明显效率不高。更好的做法是在 hive 会话开启动态分区,一次读取多个分区或者全表进行合并(视表的记录数量和集群内存选择吧),下面是开启动态分区的配置:

set hive.exec.dynamici.partition=true;

set hive.exec.dynamic.partition.mode=nonstrict;

目前使用的 hive 版本为:1.1.0

说明:感觉这个方面效果不大好,大于阈值文件其实还很小

方法四:orc 文件

如果 hive 表使用 orc 格式,则可以使用 hql 进行小文件合并。看看官方的原文描述:bash ALTER TABLE table_name [PARTITION (partition_key = 'partition_value' [, ...])] CONCATENATE; If the table or partition contains many small RCFiles or ORC files, then the above command will merge them into larger files. In case of RCFile the merge happens at block level whereas for ORC files the merge happens at stripe level thereby avoiding the overhead of decompressing and decoding the data.

目前产品环境的 hive 表没有使用 orc 格式,因为 impala 2.12.0 不支持 orc 格式,不过 impala 3.1 开始就支持 orc 了。

另外提醒,

sqoop 的增量同步会产生非常多的小文件,最好把方法二的“控制小文件合并的条件”的配置加上。
 

方法五:hdfs 命令方式1

hdfs下的多个文件合并:不适合parquet文件
我现在需要把如下图所示的HDFS里的part-00000、part-000001、part-00002、part-00003合并到part-00004

hdfs dfs -cat /trajectory/test/data/3-25/part-0000* | hdfs dfs -copyFromLocal - /trajectory/test/data/3-25/part-00004

方法六:hdfs 命令方式2

 appendToFile get merage 等也可以,自己测试过也是适合parquet文件格式

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐