Hive压缩之二 小文件合并
调研背景
当Hive输入由很多个小文件组成,由于每个小文件都会启动一个map任务,如果文件过小,以至于map任务启动和初始化的时间大于逻辑处理的时间,会造成资源浪费,甚至OOM。为此,当我们启动一个任务,发现输入数据量小但任务数量多时,需要注意在Map前端进行输入合并。当然,在我们向一个表写数据时,也需要注意输出文件大小。
输入合并
合并输入小文件,减少map数?
主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小。
举例:
a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数
b) 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
假设一个SQL任务:
Select count(1) from mb_test where date = ‘2015-01-19’ and hour = 0;
该任务的/user/hive/warehouse/naga.db/mb_test/date=2015-01-19/hour=0共有10个文件,每个文件大小为3.15M,远小于128M的小文件,总大小31.5M,正常执行会用10个map任务。
而实际上只生成了一个map任务
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
setmapred.min.split.size.per.rack=100000000;
sethive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
结论是此处的的合并是逻辑上的合并,而Hive默认已经做了输入合并,我们不需要作过多的设置。
输出合并
合并输出小文件。输出时,若是太多小文件,每个小文件会与一个block进行对应,而block存在的意义是为了方便在namenode中存储,那么过多的block将会充斥namenode的表中,待集群规模增大和运行次数增大,那么维护block的表将会过大,严重降低namenode性能。
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
我们执行以下语句:
insert overwrite table naga.mb_time selectticks string,starttime bigint, endtime bigint from naga.mb_pageinfo where starttime%10 = 7;
该语句将大表通过设定条件starttime%10 = 7选择三个字段存入小表中,观察执行的map数量和目标文件个数:
如下图,在整个运算job中会开启两个map
而只产生了一个目标文件/user/hive/warehouse/naga.db/mb_time/000000_0,
从上图中看出我们的设置生效,不会产生两个更小的文件
几个参数指标
hive.merge.mapfiles |
是否在Map-only的任务结束时合并小文件 |
true |
true |
Hive无 |
hive.merge.mapredfiles |
是否在Map-Reduce的任务结束时合并小文件 |
false |
true |
Hive无 |
hive.merge.size.per.task |
合并目标文件的大小 |
256000000 |
256000000 |
Hive无 |
hive.merge.smallfiles.avgsize |
当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge |
16000000 |
5000000 |
Hive无 |
我们要做的就是设置hive.merge.smallfiles.avgsize , 这里建议设置为5000000 = 5M , 即当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge