Spark数据倾斜及解决办法

数据倾斜

在执行shuffle操作过程中,map端按照key分配数据输出,reduce端同样也按照key进行拉取、聚合。通常每一个key对应的数据量不对等,经常出些某些key数据量比其他key多很多。这种现象导致的后果,轻则拖慢job执行时间(执行时间由最慢的task决定),重则直接OOM(数据量太大,处理完成前不能回收内存)

原因

我觉得是两个必要条件,缺一个都不发生数据倾斜,而我们打破其中一个或全部打破来解决数据倾斜。

  • 每个key对应的数据量天然不均
  • 发生shuffle操作

那么怎么定位代码中哪里出现了数据倾斜?

  • 凭经验猜测会发生shuffle的算子
  • 运行慢时。若是client模式,查看本地日志,当前还在运行的Stage、Task是哪个;若是cluster模式,查看UI,主要确定Stage中Task的数据量
  • 报OOM时查看log抛错堆栈,可以定位到某一行代码,从而知道哪一个stage,哪个一个算子。
解决办法
数据源预处理
  • 业务中,hive文件或其他数据源文件大小不均,有大有小。小文件处理很快,而大文件处理慢。如果提前对数据源数据进行一定的清洗、过滤、去重、重分区等操作,将原来不均匀的数据重新均匀放在多个文件中。
  • 同理,针对key分布不均的情况,可以考虑将Spark 运算中业务时效不敏感的shuffle操作提前放到ETL进行预处理(比如预聚合、逻辑压缩等。如果使一个key对应一条数据,最好),从而避免在Spark中进行shuffle操作,从而避免数据倾斜。
  • 从业务理解上调整key的设计。目的是让每个key对应数据量尽量差距不大。

这种方法打破数据不均条件。

过滤倾斜的key

有一些key数据量不小,但之于业务并没有什么意义,比如正常key是A_B,经常出现“_”不正常key的数据,这些key的数据可以在shuffle之前过滤掉。
这种方法在一定程度上打破数据不均条件。

提高并行度

当多个倾斜的key被分给同一个shuffle read Task时,可以尝试提高并行度。

  • 使用shuffle算子的第二参数,将不同key的数据拆分到多个Task上,避免多个倾斜key集中在一个Task中。
  • 同理在Spark SQL中设置spark.sql.shuffle.partitions(默认200),主要针对shuffle类语句(比如group by、join等)

数据再分配,一定程度上打破数据不均条件。

分段聚合

针对groupByKey、reduceByKey这类算子,将shuffle分两个阶段。第一个阶段:在原key基础上附加前缀或后缀(使用随机也好、数值范围也好。一般推荐随机,实现简单效果也好),这样同一个key被打散成不同key,进行第一阶段聚合等到多个分组的值。然后map(将每个分组key去掉前缀或后缀,恢复到从前)到第二阶段。第二阶段直接使用原key再进行一次聚合得到结果。

针对groupByKey、reduceByKey这类算子进行数据再分配的高级方式,一定程度上打破数据不均条件。

reduce join转换为map join

针对join操作,将较小RDD中的数据通过collect拉取到Driver端的内存中,然后对其创建一个广播变量;接着对另外一个RDD执行map运算,在运算中从广播变量中获取数据,与每一条数据按照key进行连接。相当于把reduce端join转换为map端join,从而避免shuffle.

这个方法打破shuffle操作条件,但是不适合广播数据量大的场景。

sample采样对倾斜key单独进行join

通过sample算子采样出一份样本来,计算最大的是哪几个key。将这几个key(倾斜key)对应的数据从原RDD中单独拆分出来,形成一个单独的RDD(A),并给每个key附上n以内的前缀随机数,从而打散每一个key,避免过于集中,不属于倾斜key的部分则组成另外一个RDD(C)。然后将另外一个被连接的RDD过滤出属于倾斜key数据的部分,形成一个新的RDD(B),不属于倾斜key的部分形成另一个新的RDD(D)。按照前面的规则把B也附上n以内的前缀随机数并进行扩容(其中每一个随机数复制一个整份数据,共n份)。然后将A与B做join形成E,C与D正常做join形成F。最后E与F做union等到结果。

针对join进行数据再分配,一定程度上打破数据不均条件,适合倾斜key少的情况。

随机扩容全量进行join

这个方法是上一个办法的升级版。不是针对倾斜key的部分扩容,而是整体进行扩容,一般选数据少的那个RDD进行扩容,另外一个RDD做随机n拆分打散。然后这两个RDD做join得到结果。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值