hive--小文件问题

  • 小文件如何产生
  • 小文件带来的影响
  • 解决方案
  • 已有的小文件
  • 小文件的产生途径
  • 参考


小文件如何产生

  • hive的底层存储是HDFS,默认的块大小是128M,通常小于默认块大小,HDFS默认也算一个block, 所以产生小文件主要有以下几种:
  • 1、数据源本身就包含有大量的小文件。
  • 2、使用spark/flink实时写hive时,根据业务的时间窗口(10s,20s)落地hive表,产生很多小文件。
  • 3、采用动态分区也会产生很多小文件。
  • 4、reduce的个数输出。默认reduce个数和落地hive文件个数一样。

小文件带来的影响

  • 1、从Hive的角度看,小文件会开很多map,一个map开一个JVM去执行,所以这些任务的初始化,启动,执行会浪费大量的资源,严重影响性能。
  • 2、HDFS存储太多小文件, 会导致namenode元数据特别大, 占用太多内存, 查询效率降低。
  • HDFS的文件元信息,包括位置、大小、分块信息等,都是保存在NameNode的内存中的。每个对象大约占用150个字节,因此一千万个文件及分块就会占用约3G的内存空间,一旦接近这个量级,NameNode的性能就会开始下降了。

解决方案

已有的小文件

  • 1.使用hadoop archive命令把小文件进行归档。
#用来控制归档是否可用
set hive.archive.enabled=true;
#通知Hive在创建归档时是否可以设置父目录
set hive.archive.har.parentdir.settable=true;
#控制需要归档文件的大小
set har.partfile.size=1099511627776;

#使用以下命令进行归档
ALTER TABLE srcpart ARCHIVE PARTITION(ds='2021-09-08', hr='12');

#对已归档的分区恢复为原文件
ALTER TABLE srcpart UNARCHIVE PARTITION(ds='2021-09-08', hr='12');

#::注意,归档的分区不能够INSERT OVERWRITE,必须先unarchive
  • 2.重建表,建表时减少reduce数量。
set mapred.reduce.tasks=100; -- 设置reduce数量

小文件的产生途径

  • 参数设置
-- 每个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输出和reduce输出进行合并的相关参数:
 
-- 设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true;
-- 设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true;
-- 设置合并文件的大小
set hive.merge.size.per.task = 134217728;
 
-- 当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000;
  • 少用动态分区,使用distribute by分区
--设置作业优先级(VERY_HIGH,HIGH,NORMAL,LOW)
set mapred.job.priority = NORMAL;
--开启中间压缩(map输出结果压缩)
set hive.exec.compress.intermediate = true;
--在Map-Reduce的任务结束时合并小文件
set hive.merge.mapfiles=true;
set hive.merge.mapredfiles = true;
--合并文件的大小,设置为块大小的两倍256M
set hive.merge.size.per.task = 134217728;
--当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge
set hive.merge.smallfiles.avgsize=134217728;
-- orc的表同时需要下面两个,其它文件可以去掉
set hive.exec.orc.default.block.size=134217728;
set hive.merge.orcfile.stripe.level=false;
-- 设置读写并发
set hive.support.concurrency=false;
set hive.support.quoted.identifiers=none;
 
 
insert overwrite table ${hivevar:item_table} partition (dt='${hivevar:item_date}')
select `(dt)?+.+`
from ${hivevar:item_table}
where dt='${hivevar:item_date}'
distribute by rand();
 
--程序解读: 使用distribute by rand() 自动产生shuffle, 将数据随机分配给reduce,避免出现较大文件。
  • 使用sequencefile作为表存储形式,不要使用textfile,在一定程度上可以减少小文件

参考