數據傾斜原因及其解決方案

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章