“”关键字:Spark,性能优化,数据倾斜
参考资料:美团技术团队

你怎么比我干得少?好吧,我再努力也,干活速度再快,也只能拖后腿了
Spark性能优化无非就是一个让Spark算得快的问题。计算得快,无非也类似于一个工厂里面干活干得快的问题,而每个工人干活的快慢呈现一个正太分布的规律分布(先不管什么是正太分布),总体上,干活的速度在平均速度附近徘徊,慢的也慢不了多少,速度快的也快不了多少。
Spark这座工厂经常会出现“木桶”的现象,“木桶”现象也被称之为“长尾效应”,如下现象
(1)“木桶”的现象:Spark任务最终的执行时间取决于最后执行结束的task的运行时间,也就是说:取决于最慢的那个任务(工厂里面干活干得最慢的那个SB)
(2)“长尾现象”同“木桶”类似,不过为了加深理解,且与实际遇到的场景更接近,所以画蛇添个足,其大致描述为:

可是,问题并不是干活最慢的那个工人懒惰,也并不是由于笨,手脚残疾等,而是由于老板分配给他的任务太多了,简单来说,假如工厂要生产接下来一年的产品,老板刚开始以为每天的订单都接近于平均订单数量,刚好工厂一共有365个工人,老板心想,这是“缘分”啊,每人在接下来的一段预定时间里生产一天的订单量(假象情况下)。
结果是:某一天的订单量为全年订单总量的10%;
很明显,有一个工人需要干得活太多了,本来速度就一般,再加上抱怨,速度也没怎么提升,于是整个生产周期大大拉长。
解决方案
参考美团技术团队的解决方案,用另一种轻松一点的家常小事来聊聊Spark性能优化的那点“小事”。
干活慢的工人实在提不了速度了,于是向上级汇报,可是这家工厂层级太多(有部分不懂装懂的管理者自以为合理的划分任务),管理者的功能很重要(不可或缺),但是偶尔会由于给他的目标过于宏观(导致数据倾斜的key-value分布不均匀),也会犯错误,这些领导包含且不仅限于以下这些:
(1)distinct
(2)groupByKey
(3)reduceByKey
(4)aggregateByKey
(5)join
(6)cogroup
(7)repartition等
某个task莫名其妙内存溢出的情况
这种情况下去定位出问题的代码就比较容易了。我们建议直接看yarn-client模式下本地log的异常栈,或者是通过YARN查看yarn-cluster模式下的log中的异常栈。一般来说,通过异常栈信息就可以定位到你的代码中哪一行发生了内存溢出。然后在那行代码附近找找,一般也会有shuffle类算子,此时很可能就是这个算子导致了数据倾斜。
但是大家要注意的是,不能单纯靠偶然的内存溢出就判定发生了数据倾斜。因为自己编写的代码的bug,以及偶然出现的数据异常,也可能会导致内存溢出。因此还是要按照上面所讲的方法,通过Spark Web UI查看报错的那个stage的各个task的运行时间以及分配的数据量,才能确定是否是由于数据倾斜才导致了这次内存溢出。
查看导致数据倾斜的key的数据分布情况
可以有很多种查看key分布的方式:
如果是Spark SQL中的group by、join语句导致的数据倾斜,那么就查询一下SQL中使用的表的key分布情况。
如果是对Spark RDD执行shuffle算子导致的数据倾斜,那么可以在Spark作业中加入查看key分布的代码,比如RDD.countByKey()。然后对统计出来的各个key出现的次数,collect/take到客户端打印一下,就可以看到key的分布情况。
根据资料,提供以下7种解决方案
(详见https://tech.meituan.com/spark_tuning_pro.html)
(1)使用Hive ETL预处理数据(给老板的数据就已经发生了调度的数据不均匀),比如数据上游Hive本来数据就不均匀
(2)解决方案二:过滤少数导致倾斜的key
(3)提高shuffle操作的并行度
(4)两阶段聚合(局部聚合+全局聚合)
(5)解决方案五:将reduce join转为map join
(6)采样倾斜key并分拆join操作
(7)使用随机前缀和扩容RDD进行join
另外,HashShuffleManager/SortShuffleManager也是重要的优化研究对象
网友评论