@Author : Spinach | GHB
@Link : http://blog.csdn.net/bocai8058
Hive表小文件治理方案
小文件是如何产生的?
- Reduce个数越多,产生的小文件越多;
- 写入hive表时,以动态分区(
set hive.exec.dynamic.partition=true
)形式写入时,会产生大量的小文件; - 数据源本身就包含众多小文件;
为什么要治理小文件?
- 从Hive的角度看,小文件会开很多map,一个map开一个JVM去执行,所以这些任务的初始化,启动,执行会浪费大量的资源,严重影响性能。
- 从HDFS的角度看,小文件太多,会导致namenode元数据对象多,占用更多的内存,从而制约了集群的扩展。
Hive的小文件治理方案
HDFS中文件的存储是以文件块(block)的形式存储在DataNode中的,block块位置信息等元数据信息是存储在namenode中的,在实际生产中,一般block块的大小设置为256MB。具体关于block块疑问,可参考《HDFS Block块大小限定依据及原则》
- 设置以下参数:
## 设置map输入合并小文件的相关参数
set mapred.max.split.size=256000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
## 设置map输出和reduce输出进行合并的相关参数
set hive.merge.mapfiles=true;
set hive.merge.mapredfiles=true;
set hive.merge.size.per.task=256000000;
set hive.merge.smallfiles.avgsize=256000000;
- 少用动态分区,用时记得按distribute by rand() 将数据随机分配给Reduce,这样可以使得每个Reduce处理的数据大体一致,例如:
insert overwrite table tableName partition(date) select * from person DISTRIBUTE BY (rand()*3);
- 针对于ORC格式存储的表,可使用concatenate命令对指定分区进行小文件合并,例如:
alter table tableName_orc partition (date="20200101") concatenate;
- 仅仅适用于ORC格式存储的表;
- 使用concatenate命令合并小文件时不能指定合并后的文件数量,虽然可以多次执行该命令,但显然不够优雅。当多次使用concatenate后文件数量不在变化,这个跟参数mapreduce.input.fileinputformat.split.minsize=256mb的设定有有有关,可设定每个文件的最小size,具体见链接;
- 只能针对分区使用concatenate命令。
Spark的小文件治理方案
- 添加参数
.config("spark.sql.adaptive.enabled", "true")
; - 添加
repartition
操作或coalesce
操作; - 添加sql hint暗示(
/*+ REPARTITION(分区数) */
),例如:
create table tableName as select /*+ REPARTITION(10) */ age,name from person where date='20200101'
insert into table tableName select /*+ REPARTITION(10) */ age,name from person where date='20200101'
insert overwrite table tableName select /*+ REPARTITION(10) */ age,name from person where date='20200101'
注意:分区数的设置根据落地数据量而定
- 少用动态分区,用时记得按
distribute by rand()
将数据随机分配给Reduce,这样可以使得每个Reduce处理的数据大体一致,例如:
insert overwrite table tableName partition(date) select * from person DISTRIBUTE BY rand()
对已存在的小文件治理方案
- 设置与【Hive的小文件治理方案】中1相同的参数;
- 使用hadoop archive命令把小文件进行归档;
- 重建表,建表时减少reduce数量;
- 重新读取表中数据,重新控制写入文件数,如:
spark.table(dwdTableName).where(s"""statis_date='$statis_date'""").coalesce(5).distinct().write.mode(SaveMode.Overwrite).insertInto(dwdTableName)
;