RICH-ATONE

hive解决小文件过多的问题

针对小文件问题,一般可以再采集端(flume)进行合并,后期的话可以针对如下方式进行解决:

相比map个数的控制复杂性,reduce个数的设定要相对简单多了,reduce的个数一般最后决定了输出文件的个数,

二者相等,如果想多输出文件的个数(这样文件变小,但有可能程序变慢),那么可以人为增加reduce个数。

果想减少文件个数,也可以手动较少reduce个数(同样可能程序变慢)。

但实际开发中,reduce的个数一般通过程序自动推定,而不人为干涉,因为人为控制的话,如果使用不当很容易造成结果不准确,且降低执行效率。

注:

同map函数一样,启动和初始化reduce也会消耗时间和资源。所以reduce的个数不宜过多,且reduce的个数决定了最终输出文件的个数,

如果reduce个数过多则会产生很多小文件,对于以后的计算也会降低效率。

当然reduce个数如果过少,也会造成单个reduce处理数据量太大也会影响程序的效率。所以一般reduce的个数最好让程序自己去推定与计算。

那么什么时候可以进行手动设定reduce数量呢?比如系统自动计算的reduce个数,因为集群资源不足,造成程序运行出现OOM(内存溢出不足)时,
可以根据推定的reduce个数手动增加数量,保证程序在跑的慢的基础上可以完整运行。

一、小文件带来的问题(造成的影响)

1.HDFS的文件包好数据块和元信息,其中元信息包括位置、大小、分块等信息,都保存在NameNode的内存中。每个对象大约占用150个字节,因此一千万文件及分块就会占用约3G的内存空间,一旦接近这个量级,NameNode的性能就会开始下降。

2.HDFS读写小文件时也会更加耗时,因为每次都需要从NameNode获取元信息,并且对应的DataNode建立连接。

3.对于MapReduce程序来说,例如从Hive的角度看,小文件会开很多map,一个map开一个JVM去执行,所以这些任务的初始化,启动,执行会浪费大量的资源,严重影响性能。

二、Hive小文件产生的原因

  • 源数据本身有很多小文件
  • 动态分区会产生大量小文件
  • reduce个数越多, 小文件越多
  • 按分区插入数据的时候会产生大量的小文件, 文件个数 = maptask个数 * 分区数
  • 注:设置map的数量不会导致小文件增多或减少,map只是处理过程的前面部分,到reduce端的数量才有可能造成小文件增加或者减少
一方面hive数据仓库中汇总表的数据量通常比源数据少的多,而且为了提升运算速度,我们会增加Reduce的数量,Hive本身也会做类似的优化
Reducer数量等于源数据的量除以hive.exec.reducers.bytes.per.reduce所配置的量(默认1G)。Reduce数量的增加也即意味着结果文件的增加,从而产生小文件的问题。
解决小文件的问题可以从两个方向入手:
①在Map前进行小文件合并
①输入合并。即在map前合并小文件。
②输出合并。即在输出结果的时候合并小文件。

三、配置Map输入合并

--每个Map最大输入大小,决定合并后的文件数
set mapred.max.split.size=256000000;

--一个节点上split的至少的大小,决定了多个data node上的文件是否需要合并
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;

四、配置hive结果合并

通过设置hive的配置项在执行结束后对结果文件进行合并:

set hive.merge.mapfiles=true#在Map-only的任务结束时合并小文件

set hive.merge.mapredfiles=true#在Map-Reduce的任务结束时合并小文件

set hive.merge.size.per.task=256*1000*1000#合并文件的大小

set hive.merge.smallfiles.avgsize=16000000#当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge

 

示例hive优化参数如下(反例):

set hive.exec.dynamic.partition.mode=nonstrict;
set hive.exec.dynamic.partition=true;
set hive.auto.convert.join=false;
set mapreduce.map.memory.mb=8192;
set mapreduce.reduce.memory.mb=8192;
set mapred.child.java.opts=-Xmx1536m;
set mapreduce.job.reduce.slowstart.completedmaps=0.8;
set mapred.reduce.tasks=20;  --此处设置了reducer的个数为20个则会生成20个文件
set hive.exec.parallel=true;

则会产生20个文件如下:

 

 

参考:

hive解决小文件过多的问题

https://cloud.tencent.com/developer/article/1767597

 https://blog.csdn.net/qq_26442553/article/details/99693490

posted on 2021-08-26 15:58  RICH-ATONE  阅读(1286)  评论(0编辑  收藏  举报

导航