彻底解决Hive小文件问题

简介: 小文件产生的原因和危害以及解决方法。

最近发现离线任务对一个增量Hive表的查询越来越慢,这引起了我的注意,我在cmd窗口手动执行count操作查询发现,速度确实很慢,才不到五千万的数据,居然需要300s,这显然是有问题的,我推测可能是有小文件。

我去hdfs目录查看了一下该目录:

微信图片_20220426213409.png


发现确实有很多小文件,有480个小文件,我觉得我找到了问题所在,那么合并一下小文件吧:

insert into test select * from table distribute by floor (rand()*5);


这里使用distribute by进行了一个小文件的合并,通过rand() * 5,保证了从map端输出的数据,最多到5个reducer,将小文件数量控制了下来,现在只有3个文件了。

微信图片_20220426213412.png


合并小文件后,再次做同样的查询,15s就完成了。确实忽略了,增量数据会导致小文件,应该在当初做的时候就做定时的小文件合并,而不是等到现在才发现。

因为这个表每天是有增量数据进去的,增量数据会单独生成一个文件,因为增量数据本身不大,日积月累就形成了大量小文件。不仅对namenode的内存造成压力,对map端的小文件合并也有很大压力。


小文件产生的原因


  • 动态分区插入数据的时候,会产生大量的小文件;


  • 数据源本身就包含有大量的小文件;


  • 做增量导入,比如Sqoop数据导入,一些增量insert等;


  • 分桶表,分桶表通常也会遇到小文件,本质上还是增量导入的问题;


  • 可以修改的表,这种Hive表是可以进行修改的,通过配置stored as orc TBLPROPERTIES ("transactional"="true"),这种表最坑,每天都会有一个快照,到后面10G大小的数据,表文件体积可以达到600G,时间越长越大;


小文件的问题有很多,实际中各种原因,由于自己的不小心,前期没有做好预防都会产生大量小文件,让线上的离线任务神不知鬼不觉,越跑越慢。


小文件的危害


  1. 给namenode内存中fsImage的合并造成压力,如果namenode内存使用完了,这个集群将不能再存储文件了;

  2. 虽然map阶段都设置了小文件合并,org.apache.hadoop.hive.ql.io.CombineHiveInputFormat,太多小文件导致合并时间较长,查询缓慢;


小文件的解决方案


彻底解决小文件,分为了两个方向,一个是小文件的预防,一个是大量小文件问题已经出现了,我们该怎么解决。


1. 小文件的预防


网上有些解决方案,是调节参数,这些参数在我使用的Hive2是默认都开启了的:

//每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;  
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)  
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 
//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000


有些公司用的版本不同,低版本可能有些配置不一样,最好检查一下上面这些配置是否设置,然后根据自己的实际集群情况进行设置。

小文件的预防,主要还是要根据小文件的产生原因,来进行预防。


  1. 动态分区插入的时候,保证有静态分区,不要误判导致产生大量分区,大量分区加起来,自然就有大量小文件;


  1. 如果源表是有大量小文件的,在导入数据到目标表的时候,如果只是insert into dis select * from origin的话,目标表通常也有很多小文件。如果有分区,比如dt, hour,可以使用distribute by dt, hour,保证每个小时的数据在一个reduce里面;


  1. 类似sqoop增量导入,还有hive一些表的查询增量导入,这些肯定是有小文件的,需要进行一周甚至一天定时任务的小文件合并。


2. 小文件的解决


上面是平时开发数据任务时候,小文件的预防,但如果由于我们的大意,小文件问题已经产生了,就需要解决了。通常就是insert overwrite了。

insert overwrite table test [partition(hour=...)] select * from test distribute by floor (rand()*5);


注:这个语句把test表的数据查询出来,overwrite覆盖test表,不用担心如果overwrite失败,数据没了,这里面是有事物性保证的,可以观察一下执行的时候,在test表hdfs文件目录下面有个临时文件夹。如果是分区表,加上partition,表示对该分区进行overwrite


如果是orc格式存储的表,还可以使用alter table test [partition(...)] concatenate进行小文件的合并,不过这种方法仅仅适用于orc格式存储的表。



目录
相关文章
|
SQL 存储 分布式计算
【Hive】(二十三)简单几招教你如何解决 Hive 中小文件过多的问题
【Hive】(二十三)简单几招教你如何解决 Hive 中小文件过多的问题
1758 0
|
SQL 分布式计算 DataWorks
同步Hive表数据报block文件不存在问题 java.io.FileNotFoundException: File does not exist
同步Hive表数据报block文件不存在问题 java.io.FileNotFoundException: File does not exist
|
6月前
|
SQL 存储 算法
【Hive】Hive 小文件过多怎么解决?
【4月更文挑战第16天】【Hive】Hive 小文件过多怎么解决?
|
12月前
|
SQL 存储 Java
Hive教程(09)- 彻底解决小文件的问题
Hive教程(09)- 彻底解决小文件的问题
564 0
|
6月前
|
SQL 存储 分布式计算
Hive【基础知识 02-2】【Hive CLI 命令行工具使用】【详细举例-包含测试脚本文件】
【4月更文挑战第7天】Hive【基础知识 02-2】【Hive CLI 命令行工具使用】【详细举例-包含测试脚本文件】
88 0
|
SQL 存储 分布式计算
Hive学习---6、文件格式和压缩
Hive学习---6、文件格式和压缩
Hive学习---6、文件格式和压缩
|
SQL 存储 分布式计算
hive 小文件问题及解决方法【重要】
hive 小文件问题及解决方法【重要】
443 0
|
存储 SQL JSON
hive文件与压缩
hive文件与压缩
hive文件与压缩
|
SQL 分布式计算 监控
使用Flume监控文件并导入到HIVE表中
使用Flume监控文件并导入到HIVE表中
|
SQL Linux 数据库
Hive 表 DML 操作——Hive 表 DML 操作——第1关:将文件中的数据导入(Load)到 Hive 表中
Hive 表 DML 操作——Hive 表 DML 操作——第1关:将文件中的数据导入(Load)到 Hive 表中
937 0