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解决小文件过多的问题
posted on 2021-08-26 15:58 RICH-ATONE 阅读(1415) 评论(0) 编辑 收藏 举报