小文件优化
小文件产生的原因
- 动态分区插入数据,产生大量小文件,从而导致map数量剧增
- reduce数量越多,小文件也可能越多(reduce的数量等于输出文件的数量)
- 数据源本身包含大量的小文件
小文件的影响
- 从hive的角度,小文件过多会启动很多map,一个map就是一个JVM进程,这些任务初始化,启动,执行会浪费大量的资源,严重影响性能
- 在hdfs中,每个小文件对象的元数据信息大约150byt。如果小文件过多会占用大量内存。这样NameNode内存容量严重制约集群的扩展
相关优化
-
小文件的预防
- 设置map和reduce个数,通用性不好
// 设置map的数量 set mapred.map.tasks =10; // 设置reduce任务数,输出文件数量对应reduce个数 set mapred.reduce.tasks=10; // 设置每个reduce处理文件最大字节长度,可以增加或减少reduce的数量 set hive.exec.reducers.bytes.per.reducer = 256000000;
- 设置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 // 设置合并文件的大小 set hive.merge.size.per.task = 256000000 // 设置reduce端输出进行合并,默认为false set hive.merge.mapredfiles = true // 控制一个job当中会有多少reduce来处理,依据的是输入文件的总大小 set hive.exec.reducers.bytes.per.reducer=256000000 // 当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。 set hive.merge.smallfiles.avgsize=16000000
- 设置map和reduce个数,通用性不好
-
小文件解决
-
distribute by
insert overwrite table test [partition(hour=...)] select * from test distribute by floor (rand()*5);
- distribute by:主要是控制在map端如何拆分数据给reduce端,其后的列用于控制落地文件数,默认采用hash算法
- rand():控制最终生成的文件个数
注意:
这个语句把test表的数据查询出来,overwrite覆盖test表,不用担心如果overwrite失败,数据没了,这里面是有事务性保证的,可以观察一下执行的时候,在test表hdfs文件目录下面有个临时文件夹。如果是分区表,加上partition,表示对该分区进行overwrite -
concatenate
// 这种方式只适用于orc文件存储格式的表 alter table TableName [partition(...)] concatenate
-