如何解决数据倾斜问题?
轉載:https://blog.csdn.net/Mr_HHH/article/details/89399518
今天在工作中遇到了數據傾斜的問題,一條SQL執行了8小時才執行完,看計劃是先join再做distinct,卡在了join上,數據量比較大,并且重復數據比較多,后續經過分析計劃,查資料,在不影響結果的前提下,改為先進行distinct,然后再join,最后在2min12s就出了結果。
在網上查找資料時,發現與這篇文章中的解決數據傾斜的辦法有相同的部分。
目前流行的大數據相關的計算框架之所以能夠處理大量的數據和計算,基本上都是依賴分布式計算的思想,即由一個通過某種組織關系連接在一起的集群來共同完成計算任務。
這是一個非常好的計算模型,無論多大的數據量,只要集群可以擴展,就能夠擴充算力,自如應對,但與此同時,也為數據傾斜的產生埋下了伏筆。
1:什么是數據傾斜?
前面提到分布式計算,是一個集群共同承擔計算任務,理想狀態下,每個計算節點應該承擔相近數據量的計算任務,然而實際情況通常不會這么理想,數據分配嚴重不均就會產生數據傾斜。我們先來給數據傾斜下個明確點的定義。
數據傾斜,指的是并行處理的過程中,某些分區或節點處理的數據,顯著高于其他分區或節點,導致這部分的數據處理任務比其他任務要大很多,從而成為這個階段執行最慢的部分,進而成為整個作業執行的瓶頸,甚至直接導致作業失敗。
舉個實際發生的例子說明下,一個spark作業,其中有個stage是由200個partition組成,在實際執行中,有198個partition在10秒內就完成了,但是有兩個partition執行了3分鐘都沒有完成,并且在執行5分鐘后失敗了。這便是典型的數據傾斜場景,通過觀察SparkUI發現這兩個partition要處理的數據是其他partition的30多倍,屬于比較嚴重的數據傾斜。
2:數據傾斜的危害
知道了什么是數據傾斜,那么它到底有什么危害,讓大家這么痛恨它的同時,又很畏懼它呢。
數據傾斜主要有三點危害:
危害一:任務長時間掛起,資源利用率下降
計算作業通常是分階段進行的,階段與階段之間通常存在數據上的依賴關系,也就是說后一階段需要等前一階段執行完才能開始。
舉個例子,Stage1在Stage0之后執行,假如Stage1依賴Stage0產生的數據結果,那么Stage1必須等待Stage0執行完成后才能開始,如果這時Stage0因為數據傾斜問題,導致任務執行時長過長,或者直接掛起,那么Stage1將一直處于等待狀態,整個作業也就一直掛起。這個時候,資源被這個作業占據,但是卻只有極少數task在執行,造成計算資源的嚴重浪費,利用率下降。
危害二:由引發內存溢出,導致任務失敗
數據發生傾斜時,可能導致大量數據集中在少數幾個節點上,在計算執行中由于要處理的數據超出了單個節點的能力范圍,最終導致內存被撐爆,報OOM異常,直接導致任務失敗。
危害三:作業執行時間超出預期,導致后續依賴數據結果的作業出錯
有時候作業與作業之間,并沒有構建強依賴關系,而是通過執行時間的前后時間差來調度,當前置作業未在預期時間范圍內完成執行,那么當后續作業啟動時便無法讀取到其所需要的最新數據,從而導致連續出錯。
可以看出,數據傾斜問題,就像是一個隱藏的殺手,潛伏在數據處理與分析的過程中,只要一出手,非死即傷。那么它又是如何產生的呢?想要解決它,我們就要先了解它。
3:為什么會產生數據傾斜?
3.1:讀入數據的時候就是傾斜的
讀入數據是計算任務的開始,但是往往這個階段就可能已經開始出現問題了。
對于一些本身就可能傾斜的數據源,在讀入階段就可能出現個別partition執行時長過長或直接失敗,如讀取id分布跨度較大的mysql數據、partition分配不均的kafka數據或不可分割的壓縮文件。
這些場景下,數據在讀取階段或者讀取后的第一個計算階段,就會容易執行過慢或報錯。
3.2:shuffle產生傾斜
在shuffle階段造成傾斜,在實際的工作中更加常見,比如特定key值數量過多,導致join發生時,大量數據涌向一個節點,導致數據嚴重傾斜,個別節點的讀寫壓力是其他節點的好幾倍,容易引發OOM錯誤。
3.3:過濾導致傾斜
有些場景下,數據原本是均衡的,但是由于進行了一系列的數據剔除操作,可能在過濾掉大量數據后,造成數據的傾斜。
例如,大部分節點都被過濾掉了很多數據,只剩下少量數據,但是個別節點的數據被過濾掉的很少,保留著大部分的數據。這種情況下,一般不會OOM,但是傾斜的數據可能會隨著計算逐漸累積,最終引發問題。
4:怎么預防或解決數據傾斜問題?
4.1.盡量保證數據源是均衡的
程序讀入的數據源通常是上個階段其他作業產生的,那么我們在上個階段作業生成數據時,就要注意這個問題,盡量不要給下游作業埋坑。
如果所有作業都注意到并謹慎處理了這個問題,那么出現讀入時傾斜的可能性會大大降低。
這個有個小建議,在程序輸出寫文件時,盡量不要用coalesce,而是用repartition,這樣寫出的數據,各文件大小往往是均衡的。
4.2.對大數據集做過濾,結束后做repartition
對比較大的數據集做完過濾后,如果過濾掉了絕大部分數據,在進行下一步操作前,最好可以做一次repartition,讓數據重回均勻分布的狀態,否則失衡的數據集,在進行后續計算時,可能會逐漸累積傾斜的狀態,容易產生錯誤。
4.3.對小表進行廣播
如果兩個數據量差異較大的表做join時,發生數據傾斜的常見解決方法,是將小表廣播到每個節點去,這樣就可以實現map端join,從而省掉shuffle,避免了大量數據在個別節點上的匯聚,執行效率也大大提升。
4.4.編碼時要注意,不要人為造成傾斜
在寫代碼時,也要多加注意不要使用容易出問題的算子,如上文提到的coalesce。
另外,也要注意不要人為造成傾斜,如作者一次在幫別人排查傾斜問題時發現,他在代碼中使用開窗函數,其中寫到over (partition by 1),這樣就把所有數據分配到一個分區內,人為造成了傾斜。
4.5.join前優化
個別場景下,兩個表join,某些特殊key值可能很多,很容易產生數據傾斜,這時可以根據實際計算進行join前優化。
如計算是先join后根據key聚合,那可以改為先根據key聚合然后再join。又如,需求是join后做distinct操作,在不影響結果的前提下,可以改為先distinct,然后再join。這些措施都是可以有效避免重復key過多導致join時傾斜。
4.6.具體問題具體分析
某些具體問題或者解決方案,不具備普遍性,但是也可以作為一種思路參考。
例如,讀入mysql數據時傾斜,這通常是由于mysql的id分布嚴重不均,中間存在跨度很大的區間造成的。解決方法有兩種,一是加大讀取時的分區數,將傾斜的區間劃分開;另一種是,先把id取出來進行等寬切割,確保每個區段的id數量一致,之后再對各區間進行數據讀取。
本文介紹了什么是數據傾斜、它的危害、產生的原因及一些常用的解決方案,希望可以幫助大家,加深對數據傾斜的認識,如果遇到類似問題,可以快速上手解決掉。
?
總結
以上是生活随笔為你收集整理的如何解决数据倾斜问题?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宠物管理系统
- 下一篇: 高等数学第七版同济大学课后习题讲解下册