方案

提高reduce task的个数(添加分区数)

  • 适用场景: key分布不均
  • 思路: 添加reduce task的个数
  • 原理: 分区数增大,可以让每个task分到key尽可能地均匀。
  • 优点: 简单
  • 缺点: 只能适用部分情况。比如有某个key的数据量远其它的key,通过这种方法没办法缓解数据倾斜。

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

  • 适用场景: 进行reduceByKey等聚合类算子
  • 思路: 两阶段聚合,就是聚合算子执行两次。第一次聚合前,将所有的key打上一个随机数,比如10以内的随机数,如"aaa"变为"2_aaa",之后进行聚合; 将第一次聚合后结果中key的随机数删除,再进行第二次聚合,最后得出结果。
  • 原理: 第一次将key加上随机数,为的是让数据分布的更均匀,解决单个task处理数据较多的问题,局部聚合后,可以减少之前某些数据量大的key的数据量,去掉随机数,再进行一个聚合就可以得出结果。
  • 优点: 对聚合类的shuffle导致导致的数据倾斜,效果很好。
  • 缺点: 对于join类的shuffle不使用,因为随机前缀,没法保证join多个数据源的key是一个前缀。

将reduce join 转为map join

  • 适用场景: 进行join操作时,其中一张表数据量很小,比如说维度表。
  • 思路: 不使用join算子进行join操作,将小表的全量数据作为Boardcast变量,使用Boardcast变量和map类算子实现join操作,直接避免了shuffle操作。
  • 原理: 就是小表数据直接广播到大表的map端,大表基于小表数据直接做关联。
  • 优点: 效果很好,不会发生shuffle,自然没有倾斜问题。
  • 缺点: join操作时必须有一个小表,小表的全量数据还不能过大。

采样倾斜key并分拆join操作

  • 适用场景: 两张表进行join操作时,两张表都比较大,其中A表有少数几个key的数据量特别大,B表的key分布比较均匀。
  • 思路: 将A表中这几个导致倾斜的key拆分出来,生成一个单独的RDD(A1),并给每个key打上n以内的随机数作为前缀;其余的key也生成一个RDD(A2)。B将几个导致倾斜的key拆分出来,每条数据膨胀成n条,分别打上0-n的前缀,生成一个单独的RDD(B1);其余的key也生成一个RDD(B2)。 A1与B1做join,A2与B2做join,最后union合并结果。
  • 原理: 将导致倾斜几个key单独拎出来做join。
  • 优点: 适用于小部分key数据量倾斜。
  • 缺点: 优点也是缺点,如果倾斜的key过多,也不合适。

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

  • 适用场景: 适用于join操作时大量数量量大的key导致数据倾斜
  • 思路: 与"采样倾斜key并分拆join操作"一致,就是不用拆了,A表所有key都加随机数,B表所有key都膨胀。
  • 原理: 膨胀就完事了。
  • 优点: 对join类的数据倾斜都能处理,并有效果显著。
  • 缺点: 对内存资源要求高。

结语

根据情况具体分析,使用哪种优化方式。

引用、参考