spark處理數據傾斜的案例

在前期的工作遇到了很多數據傾斜的案例,在此記錄下解決的心得

1) 大表join小表:

       執行某段sql,出現了Executor OOM的現象,查看其stage的狀況:

       第3個stage讀取了21.1G的數據,並shuffle寫入了2.6G的數據,由於兩個表根據字段進行join,因此必然會觸發shuffle操作。最後的stage4 需要從stage3 shuffle read 2.6G的數據,再寫入到本地,從圖中可知,stage4只shuffle讀取了1.2G的數據,然後就失敗,因此剩餘的1.4G數據傾斜到了一個分區中。

       查看下sql執行計劃:

       從圖中可知,左邊只讀取了107條記錄,而右表讀取了10億條數據,但最終執行的join方式爲sort merge join。

       sort merge join是sparksql中對兩張大表進行join的方式之一,基本原理如圖所示:

        1) 在shuffle階段,將兩張大表根據join key進行重新分區,key相同的記錄會被劃分到一個分區中
        2) 在sort階段,對單個分區節點的兩表數據,按照key進行重新排序
        3) 在merge階段,對排序好的兩張表進行join操作,通過順序移動兩邊指針,遇到相同的key就merge輸出

      這是一個很典型的小表join大表的例子,因此很容易想到對小表進行廣播,sparksql中對小表進行廣播的閾值是10M,在這裏我們通過sparksql hint手動對小表進行廣播:

        /*+ mapjoin(t_point)*/ 表示對錶t_point進行廣播

        執行該sql,查看spark的執行stage情況:

       從stage情況來看,沒有出現shuffle情況,因爲小表被廣播到了大表所在節點上,因此不會產生跨節點數據傳輸。

       從sql的執行計劃來看,執行了broadcast join。

 

2) 兩張大表join

        sql邏輯時兩張大表根據appid進行join,並且最終提取相關字段,但執行時出現了數據傾斜現象:

        從圖中可以看出,其中一個task的shuffle數據量明顯比其它task多。

        經過分析,發現是由於appid爲 100IME這個條件的記錄非常多,導致該記錄出現了數據膨脹的現象。

        由於兩張表都是大表,因此不能採用第一種對錶進行廣播的方式。

        我們將數據輸出分爲兩步,首先在兩張表中過濾掉appid爲100IME的記錄,過濾之後的appid分佈較爲均勻,因此數據很快跑出;

        第二步也就是在兩張表中篩選appid爲100IME的記錄,注意這時兩張表不能直接進行join,否則所有的數據會落到一個分區中(因爲key都是一樣)

        我們首先將兩張表篩選appid爲100IME的記錄得到兩個rdd,然後在兩個rdd進行join的地方指定分區函數,見下圖的代碼:

        

        我們在該分區函數中指定分區數量爲200,同時對key進行隨機路由,因爲這裏的key都是100IME,所以我們通過random函數讓當前記錄隨機路由到200個分區中任意一個分區中。

         執行該代碼後,觀察執行圖:

       從圖中可以看到,每個task處理的數據都很均勻,沒有出現數據傾斜現象。

       最後將兩部分的數據合併到一起就完成了整個業務流程。

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