前面介绍了如何定位数据倾斜,本文介绍如果遇到各种数据倾斜的情况该怎样优化代码。
小文件多,数据分布不均匀,使用下面的参数设置小文件合并,让每个mapper实例读取数据量大致相同。
当出现文件过大,mapper很少,导致map端读取数据很慢的时候,可以适量缩小split.size的值,以达到提高map实例数量的效果,提高数据读取效果。
出现这种情况的话,可以使用distribute by rand()打乱数据,将数据随机分发。
需要注意,此参数不可随意使用,只有出现块中数据分布不均时候才建议使用,否则会适得其反。
使用此参数后,map端不要再做复杂join、聚合,避免map端长尾,并且会带来reduce端的资源紧张,可以适度增加reducer的个数。
首先定位是哪个关联键中存在空值,然后使用rand()随机值替换join字段空值,打乱空值的分布,提高计算并行度,并且由于空值本身关联无意义,因此不会影响数据结果。
大表关联小表时,可以使用mapjoin hint,将小表广播到map端,转换成hash table加载到内存中,在mapper端和大表的分散数据做笛卡尔积,省去大表的shuffle时间,避免出现长尾。
注意,小表的定义有阈值限制,并且小表只能作为从表,不能作为主表。
且map join没有reduce任务,所以map直接输出结果,即有多少个map任务就会产生多少个结果文件
如何拆分热点数据:引入一个aggregate,提取topK热点key拆分数据,可以通过参数调整top key个数:set odps.optimizer.skew.join.topk.num=20;
Distributed MapJoin是MapJoin的升级版,适用于小表Join大表的场景,二者的核心目的都是为了减少大表侧的Shuffle和排序。
注意事项:
Join两侧的表数据量要求不同,大表侧数据在10 TB以上,小表侧数据在[1 GB, 100 GB]范围内。
小表侧的数据需要均匀分布,没有明显的长尾,否则单个分片会产生过多的数据,导致OOM(Out Of Memory)及RPC(Remote Procedure Call)超时问题。
SQL任务运行时间在20分钟以上,建议使用Distributed MapJoin进行优化。
由于在执行任务时,需要占用较多的资源,请避免在较小的Quota组运行。
使用方式:
在select语句中使用Hint提示
/*+distmapjoin(<table_name>(shard_count=<n>,replica_count=<m>))*/
并发数=shard_count * replica_count
参数说明:
table_name:目标表名。
shard_count=<n>:设置小表数据的分片数,小表数据分片会分布至各个计算节点处理。n即为分片数,一般按奇数设置。
说明
shard_count值建议手动指定, shard_count值可以根据小表数据量来大致估算,预估一个分片节点处理的数据量范围是[200 MB, 500 MB]。
shard_count设置过大,性能和稳定性会受影响; shard_count设置过小,会因内存使用过多而报错。
replica_count=<m>:设置小表数据的副本数。m即为副本数,默认为1。
说明 为了减少访问压力以及避免单个节点失效导致整个任务失败,同一个分片的数据,可以有多个副本。当并发过多,或者环境不稳定导致运行节点频繁重启,可以适当提高 replica_count,一般建议为2或3。
语法示例
适用于大表和中小表关联,且小表过滤性高的情况,使用动态过滤器,可减少大表shuffle数据量,以此提高性能。
注意,当关连键为分区字段时,可以开启动态分区裁剪,在读取完整数据前将无用分区裁剪掉。
下面的例子,如果不使用动态分区裁剪,则会将B表中的全部分区读取后再和A表关联,即使此时开启了动态过滤器,也在前期浪费了大量的读取时间。
而打开动态分区裁剪功能后,由于A表中的a列值只有20200701,B表中的20200702和20200703分区会被裁剪掉,既节省了资源,也降低了作业运行时长。
优化方案:
去重字段组合到group by 字段中,打散分组聚合去重,然后统计group by 字段的数量。
前面的内容中有过详细示例:
动态分区是指在往分区表里插入数据时,可以在分区中指定分区列,但不指定具体分区值,sql执行完才确定分区值,运行时动态批量写入。
当有K个Map Instance,N个目标分区,极端情况下会产生K* N个小文件。
MaxCompute对动态分区的处理是引入额外的一级Reduce Task,将同一个分区的数据,尽可能交给一个instance来处理写入,如有热点分区则发生长尾,优点是产生小文件少,但额外引入一级Reduce操作也耗费计算资源,因此如何保持着两者的平衡,需要认真的权衡。
若目标分区少,则没有小文件的情况存在,开启此功能不仅会增加资源浪费,还会降低性能,可以选择关闭此功能,反而可以提升性能。
数据倾斜引发的GroupBy聚合长尾,可采用groupby.skewindata参数优化:
优化原理为引入两级reduce
第一次shuffle key是group key和一个随机数(取模),将数据打散,多个reduce并发做部分聚合;
第二次shuffle key是group key,相同的key分发到同一个reduce做最终聚合;
常用于取TopN的场景中,当数据量巨大时候,可以通过两阶段聚合,增加随机列或拼接随机数,将其作为分组中一参数,提升查询性能。
示例:
为使Map阶段中各分组数据尽可能均匀,增加随机列,将其作为分组中一参数。
当日志看到dumps关键词,则说明出现了文件dump,若比较严重,可以适当调大内存参数,但不能太大,否则集群资源不足时,任务会一直排队等待资源。
当reduce无长尾时,但耗时长,可适当增大reduce并发数。
当map无长尾,但耗时长,可适当调小mapper.split.size的值,以增加mapper数量,提高并发。
希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!
本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:xinmeigg88@163.com
本文链接:http://www.ksxb.net/tnews/11518.html