在平时处理大数据量的过程中,会遇到很多数据倾斜的问题,在业务中很多坑也都踩过了,特此记录一下。
首先,有很多的数据倾斜是是在业务场景中发生的。
其次就是sql或者代码的问题了。
以订单数据为例,在之前的例行任务中都是正常运行,但是在某一天搞了一个活动,导致某一个商品的订单数据增加了100倍,然后进行一些group等的操作,这种在处理数据的时候会产生数据倾斜,因为同一个key(商品id)都shuffle到同一个节点上进行运算,其他节点都运算完成,但是这个节点因为数据多的问题,一直在执行,所以会产生数据倾斜。
解决方案:
1、调研一下数据的情况,如果数据骤增特别大,导致reduce阶段一直卡在99%或者各种container报错OOM,任务跑不出来,那么这个需要在业务上特殊处理。(如果reduce阶段99%的情况持续时间能接受,其实就不需要特殊处理了,只不过产出时间比较晚而已,可以调整一些参数就行了)
处理的方法也其实有很多的:
(1)类似于count(distinct ***)的情况改一下写法,先group by ,再在外层来一次group by聚合。因为count(distinct ***)之后的数据reduce会卡住,同一个数据都在reduce处理,比较慢。两层group by 会有预聚合,数据量表少很多,处理起来更快。
(2)真实数据就是倾斜很严重。这样的话可以单独先把倾斜的key单独拿出来计算,和其他key再聚合处理。
具体操作:
订单表(abc.order_detail),要求单个商品的成交量、成交额
先用sql过滤出来key倾斜的情况:(支付订单的数据表)
WITH big_tmp AS (
select
item_id,
count(1) as cnt
from
abc.order_detail
where
p_date = '2020-05-01'
group by
item_id
HAVING
cnt > 1
)
这个过滤出来的 big_tmp 数据集就是数据量比较大的集合。
然后在关联的过程中吧 big_tmp 的数据单独计算。
WITH big_tmp AS (
select
item_id,
count(1) as cnt
from
abc.order_detail
where
p_date = '2020-05-01'
group by
item_id
HAVING
cnt > 1
) --所有的大数据量的数据 计算
SELECT
item_id,
count(1) AS cnt,
sum(order_detail.spaend) AS total_spend
FROM
abc.order_detail
JOIN big_tmp ON order_detail.item_id = big_tmp.item_id
GROUP BY
item_id
UNION ALL
--其他数据量较小的数据 计算
SELECT
count(1) AS cnt,
sum(order_detail.spaend) AS total_spend
FROM
(
SELECT
item_id,
spaend
FROM
abc.order_detail
LEFT JOIN big_tmp ON order_detail.item_id = big_tmp.item_id
WHERE
big_tmp.item_id IS NULL -- 过滤掉大数据量的 item_id
) small
GROUP BY
item_id
这样的话就可以把数据量比较大的 item_id 单独进行计算了。倾斜的情况就会显著缓解。
如果还有问题,可以把item_id打散,进行hash,最后再把数据聚合起来,这样效率更高。(单独再出一份博客吧)
https://blog.csdn.net/iilegend/article/details/97682621