1、數據傾斜的概念
數據傾斜是在map/reduce執行程序時,reduce大部分節點執行完畢,但有一個或者少數幾個節點執行很慢,導致其他程序一直處於等待的狀態,使得整個程序執行時間較長。
2、爲什麼出現數據傾斜?
主要是在shuffle過程中,由於不同的key對應的數據量不同導致不同task處理的數據量不一樣的問題。
表現如下:
1、大部分的task執行完畢,少數幾個甚至一個task可以執行但執行很慢
2、大部分的task執行很快,但有的task突然爆oom,重複幾次
都是報這個錯,作業無法執行
3 數據傾斜的幾種處理方式
最直接的處理方式當然是增加reduce的個數啦
3.1 join操作產生的數據傾斜
3.1.1 小表關聯大表
使用map join 解決 (前提要求是內存足以裝下該全量數據)
map join概念:將做連接的小表(把重複關聯鍵少的表 (寫在關聯左側的表每有1條重複的關聯鍵時底層就會多1次運算處理。))分發到所有 MapTask 端進行 Join,從 而避免了 reduceTask
將其中做連接的小表(全量數據)分發到所有 MapTask 端進行 Join,從 而避免了 reduceTask,前提是內存足以裝下該全量數據
set hive.auto.convert.join=true;
-- //設置 MapJoin 優化自動開啓
set hive.mapjoin.smalltable.filesize=25000000
-- (默認值25M)//設置小表不超過多大時開啓 mapjoin 優化
注意:使用默認啓動該優化的方式如果出現BUG(比如MAPJOIN並不起作用),就將以下兩個屬性置爲fase手動使用MAPJOIN標記來啓動該優化
hive.auto.convert.join=false(關閉自動MAPJOIN轉換操作)
hive.ignore.mapjoin.hint=false(不忽略MAPJOIN標記)
使用map join解決小表關聯大表造成的數據傾斜問題。這個方法使用的頻率很高。
3.1.2 大表關聯大表(不能直接放入內存)
3.1.2.1 空值產生的數據傾斜
對異常值賦一個隨機值來分散key,均勻分配給多個reduce去執行
(去掉空值後join然後union空值、賦予空值新的key(rand()))
解釋:值爲 null 的所有記錄由於加上一個隨機值,原本出現在同一個 reduceTask 上的數據,打散到了多個 reduceTask 中,這樣就避免了某一個task(數據量特別大)時間運行過長。
3.1.2.2 其他
- 設置參數解決
當key值都是有效值時,解決辦法爲設置以下幾個參數
set hive.exec.reducers.bytes.per.reducer = 1000000000
也就是每個節點的reduce 默認是處理1G大小的數據,如果你的join操作也產生了數據傾斜,那麼你可以在hive中設定:
set hive.optimize.skewjoin = true;
set hive.skewjoin.key = skew_key_threshold
-- (default = 100000)
hive在運行的時候沒有辦法判斷哪個key會產生多大的傾斜,所以使用這個參數控制傾斜的閥值,如果超過這個值,新的值會發送給那些還沒有達到的reduce,一般可以設置爲總記錄數/reduce個數的2-4倍
傾斜是經常會存在的,一般select的層數超過2層,翻譯成執行計劃在3個以上的mapreduce job都會很容易產生傾斜,建議每次運行比較複雜的sql之前都可以設一下該參數,如果have no idea how to set the parameter,按官方默認(1個reduce只處理1G)就行,那麼 skew_key_threshold = 1G/平均行長. 或者默認直接設成250000000 (差不多算平均行長4個字節)
- 拆成小表
把大表切分成小表,然後分別 map join
不小不大的表關聯(小表很大,不支持map join)
優化方案
select /*+mapjoin(x)*/* from tmp a
left outer join (
select /*+mapjoin(c)*/ d.*
from
( select distinct user_guid from tmp ) c
join users d on c.user_guid = d.user_guid
) x
on a.user_guid = x.user_guid;
解釋:假如,原數據表中user_guid有上百萬個,無法直接處理。但每日的進入購卡頁的用戶不會很多,實際購卡的用戶不會很多,有點擊的資源位的人數也不會很多。進行拆分後就能轉化爲mapjoin的方式
進行操作了。
- 重新設計key
在map階段時給key加上一個隨機數,有了隨機數的key就不會被大量的分配到同一節點(odds很小),到reduce階段,把隨機數去掉即可
3.2 聚合函數導致的傾斜
容易產生數據傾斜的操作如: group by, count(distinct ***),reduceByKey、countByKey、groupByKey,aggregateByKey,cogroup、repartition
3.2.1 group by造成數據傾斜
hive.map.aggr=true
-- (默認true)這個配置項代表是否在map端進行聚合,相當於Combiner。
hive.groupby.skewindata=true (默認false)
有數據傾斜的時候進行負載均衡,當選項設定爲true,生成的查詢計劃會有兩個MR Job。
第一個MR Job,Map的輸出結果集合會隨機分佈到Reduce中,每個Reduce做部分聚合操作,並輸出結果(相同的group by key有可能被分發到不同的Reduce中),從而達到負載均衡的目的;
第二個MR Job根據預處理的數據結果按照group by key分佈到Reduce中(這個過程可以保證相同的group by key被分佈到同一個Reduce中),最後完成最終的聚合操作。
3.2.2 count(distinct )造成數據傾斜
如果數據量非常大,執行如select a,count(distinct b) from t group by a;類型的SQL時,會出現數據傾斜的問題。
解決方式:使用sum…group by代替。如
select a,sum(1) from
(select a,b from t group by a,b
)t group by a;
4 定位數據傾斜的位置
查看log文件,有時候由於log日誌過多,直接按ctrl+f 去搜索 找到最後一個error的位置往上回溯,基本能定位到錯誤,查看是由於oom錯誤還是某一個stage運行時長過長的原因導致。
參考鏈接:
- https://blog.csdn.net/leying521/article/details/93178185
- https://blog.csdn.net/weidajiangjiang/article/details/103328294