Hive小文件问题:如何产生、造成影响、解决办法

一、小文件是如何产生的

1.动态分区插入数据,产生大量的小文件,从而导致map数量剧增。

2.reduce数量越多,小文件也越多(reduce的个数和输出文件是对应的)。

3.数据源本身就包含大量的小文件。


二、小文件问题的影响

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

2.在HDFS中,每个小文件对象约占150byte,如果小文件过多会占用大量内存。这样NameNode内存容量严重制约了集群的扩展。


三、小文件问题的解决方案

从小文件产生的途经就可以从源头上控制小文件数量,方法如下:

1.使用Sequencefile作为表存储格式,不要用textfile,在一定程度上可以减少小文件。

2.减少reduce的数量(可以使用参数进行控制)。

3.少用动态分区,用时记得按distribute by分区。

=========part2===================

 一  如何开启合并小文件

  1. Spark已经默认开启合并小文件,通过自研参数spark.sql.hive.mergeFiles控制,默认为true,合并过程是单独的一个spark job
  2. 对于HiveTask的SQL任务脚本,HiveTask本身也提供了一个合并小文件功能,通过merge_flag参数控制,默认False,合并过程是一个mapreduce job
  3. 使用HiveTask跑spark任务,由于mapreduce合并小文件并行读不高,且表的stats信息是错误的可能影响后续任务执行,建议大家直接使用Spark自带的合并小文件功能
  4. 合并小文件工具mergefile也是mapreduce job,与HiveTask提供的合并小文件是一样的原理,都是mapreduce job,都有并行读不高,表的stats信息有误的问题,谨慎使用
  5. 合并小文件问题汇总:10.4 合并小文件和压缩数据汇总
  6. HiveTask与合并小文件mergefile工具使用文档:4.8.1 HiveTask执行SQL及合并小文件工具使用说明

二  查看自己的任务到底产生了多少个文件

除了使用hdfs命令查看之外,还可以通过执行计划图得到小文件信息:

Hive小文件问题:如何产生、造成影响、解决办法_第1张图片

Hive小文件问题:如何产生、造成影响、解决办法_第2张图片

可以通过bytes_of_written_output / number_of_written_files 计算得到平均文件大小,以此评估是否有小文件问题.

注意:开启合并小文件之后,上图的数值不会变,即该方法得到的数字是合并小文件之前的状态

三  如何减少产生文件个数以及合并小文件stage执行慢的解决方案

Spark写入文件数的细节:

    对于动态分区表:number_of_written_files <=  number_of_tasks * number_of_dynamic_partitions     (即 产生的文件个数 <= output stage的task个数 * 动态分区的个数)

    若上图的number of dynamic part为0,说明该sql写入的表是静态分区,在表目录下产生的文件数就是number_of_written_files

1. 如果shuffle数据量不大,可以调小spark.sql.shuffle.partitions参数的值,直接减少partition个数来减少number_of_tasks,依上面公式,产生的合并小文件数目也会减少,以减少合并小文件stage的计算量来提高运行速度,详见3. Spark任务调优技巧

2. 如果中间shuffle数据量很大,最后output的数据量较小时,可以启用自适应执行的特性(spark.sql.adaptive.enabled=true; spark.sql.adaptive.repartition.enabled=true;)自动的减小partition个数

3. 如果上面两种方式都不能解决,可以尝试如下方式修改:

     设置spark.sql.repartitionBeforeWrite.enabled=true,使output stage阶段按动态分区健做repartition,此方法与下面的sql等效,但注意可能会引入数据倾斜的问题

     

# 原SQL

insert overwrite table xxx partition (p1, p2) select ... from  ...

# 优化后的SQL

insert overwrite table xxx partition (p1, p2) select ... from  ...  distribute by  p1, p2

4. 如果上述方式都无法解决,请重新评估业务模型,优化表结构,减少动态分区数量。


四、对于已有的小文件,我们可以通过以下几种方案解决:

1.使用hadoop archive命令把小文件进行归档。

2.重建表,建表时减少reduce数量。

3.通过参数进行调节,设置map/reduce端的相关参数,

即:采用CombineTextInputFormat

参数调节细节如下:


设置map输入合并小文件的相关参数:

//每个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 = 256*1000*1000

//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。

set hive.merge.smallfiles.avgsize=16000000

你可能感兴趣的:(Hadoop,大数据,hadoop,hdfs,小文件)