关于hive on spark的distribute by和group by使用以及小文件合并问题

欢迎关注交流微信公众号:小满锅

问题导言

最近在使用hive时,发现一些任务的因为使用mapreduce的缘故,跑的太慢了,才几十个G的数据就经常跑一个多小时,于是有了切换spark的想法。
但是刚刚切换了spark,第二天发现跑出来的数据文件数大大增加,而且每个文件都非常小,导致下游spark任务为了每个小文件都启动一个task,申请资源对于spark来说是非常消耗资源的,任务又大大延迟了。
查了下关于spark合并小文件,目前有几个参数会提供参考。

输入端


set mapred.max.split.size=256000000;
设置:每个Map最大输入大小,这个值决定了合并后文件的数量;

set mapred.min.split.size.per.node=100000000;
设置:一个节点上split的至少的大小,这个值决定了多个DataNode上的文件是否需要合并;

set mapred.min.split.size.per.rack=100000000;
设置:一个交换机下split的至少的大小,这个值决定了多个交换机上的文件是否需要合并;

set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
设置:输入端map合并小文件。

输出端

这个是hive on mapreduce的合并小文件参数:

set hive.merge.mapfiles=true;
设置:启用小文件合并 - Map-Only作业,默认trueset hive.merge.mapredfiles=true;
设置:启用小文件合并 - Map-Reduce作业,默认false;

hive.merge.size.per.task=268534456;
设置:合并后所需每个文件的大小,默认256MB;这个数值是个约数,合并后文件大小会有上下浮动。

set hive.merge.smallfiles.avgsize=16777216;
设置:小文件平均大小合并阈值,默认16MB;

上面是针对hive on mapreduce的调参,但是换了spark后,就需要调整这些了

set hive.merge.sparkfiles=true;
设置:启用小文件合并 - Spark 作业,默认false;

有教程是这个样子,但是呢,会有一些问题,目前社区对spark合并小文件支持还不够完善,有些版本,或者有些公司的hive on spark可能这个参数设置效果没用或者根本不明显
但是目前首有介绍其他办法,可以做到这个合并小文件

SET
  spark.sql.adaptive.enabled=true;
SET
  spark.sql.adaptive.shuffle.targetPostShuffleInputSize = 512MB;

这两个参数能够自适应调整文件大小,但是呢仅仅靠这两个参数还不够用。因为它只能调整shuffle的分区,如果过于分区输出的文件数过小(比如只有十几M),而分区数有非常多。比如shuffle分区有200个,每个分区Read512MB,Output 20M,那么就有200个20M的小文件了。
有人会想着,将spark.sql.adaptive.shuffle.targetPostShuffleInputSize参数调大,但是这个不可控,因为你不能确定每个任务的十几Output是多少,所以就会有问题,而且这样每个任务都要去调整这个参数,非常不友好,再说了,万一shuffle分区Output只有1M,你这个值得调到多大,那么分区Read和父分区存储得有多大压力。

distribute by去重新调整数据分布

在上面的基础上,我们可以使用distribute by多进行一次shuffle。
原理就是因为spark.sql.adaptive.shuffle.targetPostShuffleInputSize它只能控制每个分区的Read的大小,而随着数据量增加,每个分区的read又被固定限制,导致分区数增加不可控,从而每个分区可能输出数据量非常小的文件。那么这时候,我们只需要在原来分散零碎的数据基础上,再增加一次shuffle,也就是进行一次distribute by。在这个distribute by过程中,分区read是512M左右,而单纯的distribute by不会进行过滤之类的,所以每个分区相当于一定要读取512M的数据,然后再将它们写出512M,那么就可以将那些小文件合并了。

distribute by和Group by

group by是根据字段去分组,做聚合计算,它的执行是在select之前。
而distribute是在select之后了。
注意如果group by和distribute by字段相同的话,效果会抵消,只会进行一次shuffle。这个还有待验证,会持续更新。

你可能感兴趣的:(hive,spark,mapreduce,spark,Hive,大数据,distribute,distribute,by)