【Spark】数据倾斜

一、含义、危害

计算数据时,数据分散度不够,导致大量数据集中到一台或几台机器上计算。

局部计算远低于平均计算速度,整个过程过慢。
部分任务处理数据量过大,可能OOM,任务失败,进而应用失败。
1

二、现象、原因

1、现象:(Spark日志或监控)

1、Executor lost、(Driver)OOM、Shuffle过程出错;
2、正常运行任务突然失败;
3、单个Executor执行时间特别久,整体任务卡在某个阶段不结束;

Spark Streaming更容易出现数据倾斜,特别是包含SQL的join、group操作,因为内存分配不多,很容易出现数据倾斜,造成OOM。

2、原因

数据倾斜只会发生在shuffle阶段。进行shuffle时,必须将各个相同Key拉取到某个节点的一个task进行处理,如按照key进行聚合或join,某个key对应数据量特别大,就会发生数据倾斜。

触发shuffle算子:distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等。

三、定位

1、Spark Web UI

查看各个task分配的数据量,确定是不是分配数据不均匀导致。

  1. 某个Task执行特别慢
    1) 知道触发shuffle常用算子;
    2)从日志找到运行到第几个stage,再在Spark Web UI查看各个task分配数据量。如果严重不均,大概率发生了数据倾斜。
    3)由stage划分原理推算出问题代码,再精准定位shuffle类算子。(这部分需要对Spark源码有深入理解)

  2. 某个Task莫名奇妙OOM
    直接看yarn-client/cluster模式下log中的异常栈,

2、通过Key统计

由于数据巨大,可以对数据进行抽样,统计出现次数,根据次数大小取出前几个。如果多数分布均匀,个别数据大若干数量级,则说明发生了数据倾斜。

四、解决

1、避免数据源的数据倾斜

  1. 过滤异常数据
    内容:异常/空值正确处理;视情况忽略对结果影响不大的无效数据;有效数据:自定义Partitioner,将不均匀的数据做一次hash,打散后让它并行度变大,再汇集。

  2. Hive ETL预处理数据
    内容:预警线通过Hive ETL对数据按照Key进行聚合,或其他表进行join,Spark作业不再需要shuffle原子进行这类操作。
    优劣:完全规避掉了数据倾斜,Spark作业性能大幅度提升。但治标不治本,只是将问题前移。
    适用:Spark响应要求高,执行次数不多,可以放到前面,提供更好的用户体验。

2、过滤少数导致倾斜的Key

内容:将少数数据量特别的key,对作业执行和计算结果不重要,干脆直接过滤。
优劣:实现简单,效果很好。但适用场景不多,大多数情况,导致倾斜的Keyh很多,并不算少数几个。

3、提高shuffle操作并行度

内容:设置shuffle算子执行shuffle read task数量,参数spark.shuffle.partitions可以代表并行的,默认200,可以调大。原本多个key分配给task的数量从一个变多个,从而让每个task处理比原来更少的数据。
优劣:实现简单,可以有效缓解,但没有彻底解决。
3

4、两阶段聚合(局部聚合+全局聚合)

内容:第一次局部聚合,每个key前面都打上一个随机数,执行reduceByKey等局部聚合,然后将各个key前缀去掉,再次进行全局聚合操作,可以得到最终结果
优劣:适用reduceByKey/goup by等聚合操作(分组操作),但join类shuffle操作,还得用其他解决方案。
4

5、将reduce join转为map join

内容:大小表(<2G)关联,可以不用join算子,而适用Broadcast变量与map类算子实现join操作,进而规避掉shuffle类操作。Broadcast变量获取较小RDD全量数据,与当前RDD的每一条按照key进行比对,相同连接。
优劣:join类操作效果很好,但只适用大小表情况。小表较大会OOM。

6、采样倾斜key并分拆join操作

适用:两个RDD/Hive表进行join时,如果数据量都比较大,出现数据倾斜。如果一个RDD少数key数据量过大,另一个RDD所有key都分布均匀。
内容:对少数几个数据量多大的key,sample采样出数据量最大的几个key,然后将这几个key从原来RDD拆分出来,形成一个单独RDD,给每个key都打上n以内随机数作为前缀,需要join的另一个RDD,也过滤出来对应key形成单独RDD,将每条数据膨胀成n条数据,附加0-n前缀,不会导致倾斜的大部分key也形成另一个RDD。此时,原先相同key打散成n份,分散到多个task进行join。剩下的RDD照常即可,最后将两次join结果union合并就得到最终join结果。
优劣:只是几个key导致倾斜,只需将其打散,然后另外一份对应key的RDD扩容n倍。但如果倾斜key特别多,如成千上万,就不适合。

7、使用随机前缀和扩容RDD进行

内容:与方案六类似,进行join操作时,RDD中大量key导致数据。都是A_RDD打上随机附加数,B_RDD进行扩容。不同之处在于,方案六是针对少数key,这一方案是针对大量倾斜key,没法将部分key拆分出来,只能对整个RDD进行数据扩容,对内存资源要求很高。
优劣:join类型数据倾斜都能出来,效果显著,当然更多是缓解,而不是彻底避免。但扩容对内存资源要求很高。

8、组合使用

内容:先用方案一和二预处理一部分数据,其次可以对shuffle提升并行度,最后可以针对不同聚合或join操作,选择一种方案进行优化。

9、其他角度:

业务角度:比如上海数据特别多,可以单独count,最后和其他城市整合;
程序层面:count(distinct) 导致只有一个reduce,可以在group外面包一层count;
调参方面:Spark自带很多参数,合理利用可以解决大部分问题。

五、参考

1、Spark性能优化之道——解决Spark数据倾斜(Data Skew)的N种姿势
2、Spark性能优化指南——高级篇
3、漫谈千亿级数据优化实践:数据倾斜(纯干货)
4、Spark 数据倾斜及其解决方案
5、细品数据倾斜(建议收藏)
6、一文带你搞清楚什么是“数据倾斜”
7、面试必问&数据倾斜

猜你喜欢

转载自blog.csdn.net/HeavenDan/article/details/115006042