数据倾斜定义:顾名思义,就是大量相似或相同数据聚集在一个块的节点里,导致计算和资源分配不均导致的计算缓慢(长尾)问题。
数据倾斜原因:
count(distinct field)
group by
NULL 空值
Shuffle (概率最高、发生最普遍的数据倾斜问题,本文重点讲述这个)
###################################################
先说解决方案:
1.相同值打散
各个论坛、博文写的最多的一种,最好理解的,对于NULL、空字符串、等可以找到的值,加rand打散。
concat_ws('_',field,rand())
重点关注 concat和 concat_ws 的区别是什么,面试和开发中的坑 经常遇见。
2.全局打散
主要解决的场景是大表和大表进行关联Join,注意如果是小表的话,直接mapjoin 采用广播即可解决。
大表和大表全局打散的思路:就是对左表(假设左表键倾斜)进行rand打散,本例举例10倍(注意这里还有优化空间,就是方法三),对右表进行explode,行转列,膨胀10倍。代码实操:
3.局部打散
局部打散主要解决超大的两张进行关联,在公司某搜索场景下,A、B表为不固定倾斜键,百亿和十亿的数据计算,为提升性能,特封装此方法。查找倾斜键,并只对倾斜键进行膨胀,如果膨胀10倍,注意右表是11倍的行转列。
# 伪代码:不理解可以再提问
select A.window_nums,
R.uid_concat
from (
select case when replierUid ='0' or replierUid is null then rand()
when window_nums > 100000 then concat_ws('_',replierUid,cast(ceiling(rand() * 10) as int))
from(
select
row_number() over(partition by if(replierUid ='0',rand(),replierUid) order by aid) as window_nums
from table_a
) A1
) A left outer join(
select *,concat_ws('_',uid, rand_num) as uid_concat
from R lateral view explode(getGenergeCode(10)) tmp_tbl as rand_num
union all
select *,null,concat_ws('_',uid) as uid_concat
from R
) R ON (A.touid_concat =R.uid_concat)
/**
* 输入
* @author :费元星
* @param key 输入数值
* @return 返回容积为数值大小,步长为1的数组
* @Demo : spark.udf.register("getGenergeCode", DataCenterUtils.getGenergeCode _)
*/
def getGenergeCode(key: Int): Array[Int] = {
return scala.Array.range(1, key + 1, 1)
}
def main(args: Array[String]): Unit = {
for (x <- getGenergeCode(10)) {
print(" " + x)
}
println()
}
/** spark.udf.register("getGenergeCode", DataCenterUtils.getGenergeCode _) */
4.在局部打散基础上,可以采用局部多段打散,目前生产环境中还未遇到,感兴趣的网友可以试试这个思路。
5.一顿操作猛如虎,有没有更牛的解决方案,答案有:采用Spark Dce,百度和英特尔联合开发的基于硬件的shuffle解决方案,和负责人在内部分享会上交流过,形成一个共同的结论,如果能在集群底层将各种问题封装好,不暴露给使用用户RD是最佳的方案。
6.当然除此之外,开源也有一些解决方案,AQE等,后面有时间可以再出一篇AQE源码详解,也有一些没解决很好的问题,例如倾斜键识别。