在平時處理大數據量的過程中,會遇到很多數據傾斜的問題,在業務中很多坑也都踩過了,特此記錄一下。
首先,有很多的數據傾斜是是在業務場景中發生的。
其次就是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