发现数据倾斜的时候,不要急于提高 executor 的资源,修改参数
或是修改程序,首先要检查数据本身,是否存在异常数据。
1、数据问题造成的数据倾斜
找出异常的 key
如果任务长时间卡在最后最后 1 个(几个)任务,首先要对 key 进行
抽样分析,判断是哪些 key 造成的。
选取 key,对数据进行抽样,统计出现的次数,根据出现次数大小排序取
出前几个。
比如:
df.select(“key”).sample(false,0.1).(k=>(k,1)).reduceBykey(+).ma
p(k=>(k._2,k._1)).sortByKey(false).take(10)
如果发现多数数据分布都较为平均,而个别数据比其他数据大上若
干个数量级,则说明发生了数据倾斜。
经过分析,倾斜的数据主要有以下三种情况:
1、null(空值)或是一些无意义的信息()之类的,大多是这个原因
引起。
2、无效数据,大量重复的测试数据或是对结果影响不大的有效数
据。
3、有效数据,业务导致的正常数据分布。
解决办法
第 1,2 种情况,直接对数据进行过滤即可(因为该数据对当前业
务不会产生影响)。
第 3 种情况则需要进行一些特殊操作,常见的有以下几种做法
(1) 隔离执行,将异常的 key 过滤出来单独处理,最后与正常数据
的处理结果进行 union 操作。
(2) 对 key 先添加随机值,进行操作后,去掉随机值,再进行一次
操作。
(3) 使用 reduceByKey 代替 groupByKey(reduceByKey 用于对每个
key 对应的多个 value 进行 merge 操作,最重要的是它能够在本地先进行
merge 操作,并且 merge 操作可以通过函数自定义.) (4) 使用 map join。
案例
如果使用 reduceByKey 因为数据倾斜造成运行失败的问题。具体操
作流程如下:
(1) 将原始的 key 转化为 key + 随机值(例如 Random.nextInt)
(2) 对数据进行 reduceByKey(func)
(3) 将 key + 随机值 转成 key
(4) 再对数据进行 reduceByKey(func)
案例操作流程分析:
假设说有倾斜的 Key,我们给所有的 Key 加上一个随机数,然后进
行 reduceByKey 操作;此时同一个 Key 会有不同的随机数前缀,在进行
reduceByKey 操作的时候原来的一个非常大的倾斜的 Key 就分而治之变成
若干个更小的 Key,不过此时结果和原来不一样,怎么破?进行 map 操
作,目的是把随机数前缀去掉,然后再次进行 reduceByKey 操作。(当
然,如果你很无聊,可以再次做随机数前缀),这样我们就可以把原本倾
斜的 Key 通过分而治之方案分散开来,最后又进行了全局聚合
注意 1: 如果此时依旧存在问题,建议筛选出倾斜的数据单独处
理。最后将这份数据与正常的数据进行 union 即可。
注意 2: 单独处理异常数据时,可以配合使用 Map Join 解决。
2、spark 使用不当造成的数据倾斜
提高 shuffle 并行度
dataFrame 和 sparkSql 可以设置 spark.sql.shuffle.partitions
参数控制 shuffle 的并发度,默认为 200。
rdd 操作可以设置 spark.default.parallelism 控制并发度,默认
参数由不同的 Cluster Manager 控制。
局限性: 只是让每个 task 执行更少的不同的 key。无法解决个别
key 特别大的情况造成的倾斜,如果某些 key 的大小非常大,即使一个
task 单独执行它,也会受到数据倾斜的困扰。
使用 map join 代替 reduce join
在小表不是特别大(取决于你的 executor 大小)的情况下使用,可
以使程序避免 shuffle 的过程,自然也就没有数据倾斜的困扰了.(详细见
http://blog.csdn.net/lsshlsw/article/details/50834858、
http://blog.csdn.net/lsshlsw/article/details/48694893) 局限性: 因为是先将小数据发送到每个 executor 上,所以数据量
不能太大。