Spark 数据倾斜解决方法

11 篇文章 0 订阅

Spark 数据倾斜

Spark 中的数据倾斜问题主要指 shuffle 过程中出现的数据倾斜问题,是由于不同的 key对应的数据量不同导致的不同 task 所处理的数据量不同的问题。

  • 例如,reduce 点一共要处理 100 万条数据,第一个和第二个 task 分别被分配到了 1 万条数据,计算 5 分钟内完成,第三个 task 分配到了 98 万数据,此时第三个 task 可能需要 10小时完成,这使得整个 Spark 作业需要 10 个小时才能运行完成,这就是数据倾斜所带来的后果。

  • 注意,要区分开数据倾斜与数据量过量这两种情况,数据倾斜是指少数 task 被分配了绝大多数的数据,因此少数 task 运行缓慢;数据过量是指所有 task 被分配的数据量都很大,相差不多,所有 task 都运行缓慢。

数据倾斜的表现

  • Spark 作业的大部分 task 都执行迅速,只有有限的几个 task 执行的非常慢,此时可能出现了数据倾斜,作业可以运行,但是运行得非常慢;

  • Spark 作业的大部分 task 都执行迅速,但是有的 task 在运行过程中会突然报出 OOM,反复执行几次都在某一个 task 报出 OOM 错误,此时可能出现了数据倾斜,作业无法正常运行。

定位数据倾斜问题

  • 查阅代码中的 shuffle 算子,例如 reduceByKey、countByKey、groupByKey、join 等算 子,根据代码逻辑判断此处是否会出现数据倾斜;

  • 查看 Spark 作业的 log 文件,log 文件对于错误的记录会精确到代码的某一行,可以根 据异常定位到的代码位置来明确错误发生在第几个 stage,对应的 shuffle 算子是哪一个;

解决方法一:聚合原数据

如果Spark作业的数据源来源于hive,那么可以先在hive表中对数据先进性聚合,例如按照key进行分组,将同一key对应的所有value用一种特殊的格式拼接到一个字符串中,之后进行map即可。

解决方法二:过滤可能导致数据倾斜的原数据

如果在Spark作业中允许丢弃某些数据,那么可以考虑将可能导致数据倾斜的 key 进行 过滤,滤除可能导致数据倾斜的 key 对应的数据,这样,在Spark作业中就不会发生数据倾斜了。

解决方法三:提高 suffle 操作中的 reduce 并行度

如果方法一和方法二都没有很好解决问题,可以考虑提高suffle过程中的reduce端并行度,reduce端并行度的提高就增加了reduce端的task的数量,那么每个task分配到的数据量就会相应减少,缓解数据倾斜问题。

rdd.reduceByKey(new function(),1000)这样写就可以,这时reduce端的task就是1000

解决方法四:使用随机 key 实现双重聚合

当使用了类似groupByKey, reduceByKey这样的算子时,可以考虑实现双重聚合

.map(x => (((new util.Random).nextInt(randomNumber) + "_" + x._1 ), x._2)) 
.reduceByKey((x, y) => (x + y )) 
.map(x => ((x._1.split("_")(1) ), x._2)) 
.reduceByKey((x, y) => (x + y ))

首先,通过 map 算子给每个数据的 key 添加随机数前缀,对 key 进行打散,将原先一 样的 key 变成不一样的 key,然后进行第一次聚合,这样就可以让原本被一个 task 处理的数 据分散到多个 task 上去做局部聚合;随后,去除掉每个 key 的前缀,再次进行聚合。

解决方法五:将 reduce join 转换为 map join

正常情况下,join 操作都会执行 suffle 过程,并且执行的都是 reduce join。

如果一个 RDD 是比较小的,可以采用 广播小 RDD 全局数据 + map 算子 => 实现与 join 同样的效果,也就是 map join 。

RDD 是并不能进行广播的,只能将 RDD 内部的数据通过 collect 拉取到 Driver 内 存然后再进行广播

解决方法六:sample 采样对倾斜 key 单独进行 join

当由单个 key 导致数据倾斜时,可以将发生数据倾斜的 key 单独提取出来,组成一个 RDD,然后用这个原本会导致倾斜的 key 组成的 RDD 和其他 RDD 单独 join,此时,根据 Spark 的运行机制,此 RDD 中的数据会在 shuffle 阶段被分散到多个 task 中去进行 join 操作。

对于 RDD 中的数据,可以将其转换为一个中间表,或者是直接使用 countByKey()的方 式,看一个这个 RDD 中各个 key 对应的数据量,此时如果你发现整个 RDD 就一个 key 的 数据量特别多,那么就可以考虑使用这种方法。

当数据量非常大时,可以考虑使用 sample 采样获取 10%的数据,然后分析这 10%的数 据中哪个 key 可能会导致数据倾斜,然后将这个 key 对应的数据单独提取出来。

解决方法七:使用随机数扩容进行 join

  1. 选择一个 RDD,使用 flatMap 进行扩容,对每条数据的 key 添加数值前缀(1~N 的数 值),将一条数据映射为多条数据;(扩容)
  2. 选择另外一个 RDD,进行 map 映射操作,每条数据的 key 都打上一个随机数作为前缀 (1~N 的随机数);(稀释)
  3. 将两个处理后的 RDD,进行 join 操作
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值