原理
為數(shù)據(jù)量特別大的Key增加隨機前/后綴棍潘,使得原來Key相同的數(shù)據(jù)變?yōu)镵ey不相同的數(shù)據(jù),從而使傾斜的數(shù)據(jù)集分散到不同的Task中,徹底解決數(shù)據(jù)傾斜問題亦歉。Join另一則的數(shù)據(jù)中恤浪,與傾斜Key對應(yīng)的部分數(shù)據(jù),與隨機前綴集作笛卡爾乘積肴楷,從而保證無論數(shù)據(jù)傾斜側(cè)傾斜Key如何加前綴水由,都能與之正常Join。
案例
通過如下SQL赛蔫,將id為9億到9.08億共800萬條數(shù)據(jù)的id轉(zhuǎn)為9500048或者9500096砂客,其它數(shù)據(jù)的id除以100取整。從而該數(shù)據(jù)集中呵恢,id為9500048和9500096的數(shù)據(jù)各400萬鞠值,其它id對應(yīng)的數(shù)據(jù)記錄數(shù)均為100條。這些數(shù)據(jù)存于名為test的表中渗钉。
對于另外一張小表test_new彤恶,取出50萬條數(shù)據(jù),并將id(遞增且唯一)除以100取整鳄橘,使得所有id都對應(yīng)100條數(shù)據(jù)声离。
INSERT OVERWRITE TABLE test
SELECT CAST(CASE WHEN id < 908000000 THEN (9500000 + (CAST (RAND() * 2 AS INT) + 1) * 48 )
ELSE CAST(id/100 AS INT) END AS STRING),
name
FROM student_external
WHERE id BETWEEN 900000000 AND 1050000000;
INSERT OVERWRITE TABLE test_new
SELECT CAST(CAST(id/100 AS INT) AS STRING),
name
FROM student_delta_external
WHERE id BETWEEN 950000000 AND 950500000;
通過如下代碼(具體代碼請點擊“閱讀原文”),讀取test表對應(yīng)的文件夾內(nèi)的數(shù)據(jù)并轉(zhuǎn)換為JavaPairRDD存于leftRDD中瘫怜,同樣讀取test表對應(yīng)的數(shù)據(jù)存于rightRDD中术徊。通過RDD的join算子對leftRDD與rightRDD進行Join,并指定并行度為48鲸湃。
從下圖可看出赠涮,整個Join耗時1分54秒,其中Join Stage耗時1.7分鐘唤锉。
通過分析Join Stage的所有Task可知世囊,在其它Task所處理記錄數(shù)為192.71萬的同時Task 32的處理的記錄數(shù)為992.72萬,故它耗時為1.7分鐘窿祥,遠高于其它Task的約10秒株憾。這與上文準備數(shù)據(jù)集時,將id為9500048為9500096對應(yīng)的數(shù)據(jù)量設(shè)置非常大晒衩,其它id對應(yīng)的數(shù)據(jù)集非常均勻相符合嗤瞎。
現(xiàn)通過如下操作,實現(xiàn)傾斜Key的分散處理
將leftRDD中傾斜的key(即9500048與9500096)對應(yīng)的數(shù)據(jù)單獨過濾出來听系,且加上1到24的隨機前綴贝奇,并將前綴與原數(shù)據(jù)用逗號分隔(以方便之后去掉前綴)形成單獨的leftSkewRDD
將rightRDD中傾斜key對應(yīng)的數(shù)據(jù)抽取出來,并通過flatMap操作將該數(shù)據(jù)集中每條數(shù)據(jù)均轉(zhuǎn)換為24條數(shù)據(jù)(每條分別加上1到24的隨機前綴)靠胜,形成單獨的rightSkewRDD
將leftSkewRDD與rightSkewRDD進行Join掉瞳,并將并行度設(shè)置為48毕源,且在Join過程中將隨機前綴去掉,得到傾斜數(shù)據(jù)集的Join結(jié)果skewedJoinRDD
將leftRDD中不包含傾斜Key的數(shù)據(jù)抽取出來作為單獨的leftUnSkewRDD
對leftUnSkewRDD與原始的rightRDD進行Join陕习,并行度也設(shè)置為48霎褐,得到Join結(jié)果unskewedJoinRDD
通過union算子將skewedJoinRDD與unskewedJoinRDD進行合并,從而得到完整的Join結(jié)果集
具體實現(xiàn)代碼如下该镣。(具體代碼請點擊“閱讀原文”)
從下圖可看出冻璃,整個Join耗時58秒,其中Join Stage耗時33秒损合。
通過分析Join Stage的所有Task可知
由于Join分傾斜數(shù)據(jù)集Join和非傾斜數(shù)據(jù)集Join省艳,而各Join的并行度均為48,故總的并行度為96
由于提交任務(wù)時嫁审,設(shè)置的Executor個數(shù)為4跋炕,每個Executor的core數(shù)為12,故可用Core數(shù)為48土居,所以前48個Task同時啟動(其Launch時間相同)枣购,后48個Task的啟動時間各不相同(等待前面的Task結(jié)束才開始)
由于傾斜Key被加上隨機前綴,原本相同的Key變?yōu)椴煌腒ey擦耀,被分散到不同的Task處理棉圈,故在所有Task中,未發(fā)現(xiàn)所處理數(shù)據(jù)集明顯高于其它Task的情況
實際上眷蜓,由于傾斜Key與非傾斜Key的操作完全獨立分瘾,可并行進行。而本實驗受限于可用總核數(shù)為48吁系,可同時運行的總Task數(shù)為48德召,故而該方案只是將總耗時減少一半(效率提升一倍)。如果資源充足汽纤,可并發(fā)執(zhí)行Task數(shù)增多上岗,該方案的優(yōu)勢將更為明顯。在實際項目中蕴坪,該方案往往可提升數(shù)倍至10倍的效率肴掷。
總結(jié)
適用場景
兩張表都比較大,無法使用Map則Join背传。其中一個RDD有少數(shù)幾個Key的數(shù)據(jù)量過大呆瞻,另外一個RDD的Key分布較為均勻。
解決方案
將有數(shù)據(jù)傾斜的RDD中傾斜Key對應(yīng)的數(shù)據(jù)集單獨抽取出來加上隨機前綴径玖,另外一個RDD每條數(shù)據(jù)分別與隨機前綴結(jié)合形成新的RDD(相當于將其數(shù)據(jù)增到到原來的N倍痴脾,N即為隨機前綴的總個數(shù)),然后將二者Join并去掉前綴梳星。然后將不包含傾斜Key的剩余數(shù)據(jù)進行Join赞赖。最后將兩次Join的結(jié)果集通過union合并滚朵,即可得到全部Join結(jié)果。
優(yōu)勢
相對于Map則Join前域,更能適應(yīng)大數(shù)據(jù)集的Join始绍。如果資源充足,傾斜部分數(shù)據(jù)集與非傾斜部分數(shù)據(jù)集可并行進行话侄,效率提升明顯。且只針對傾斜部分的數(shù)據(jù)做數(shù)據(jù)擴展学赛,增加的資源消耗有限年堆。
劣勢
如果傾斜Key非常多,則另一側(cè)數(shù)據(jù)膨脹非常大盏浇,此方案不適用变丧。而且此時對傾斜Key與非傾斜Key分開處理,需要掃描數(shù)據(jù)集兩遍绢掰,增加了開銷痒蓬。
關(guān)注我的公眾號,后臺回復(fù)【JAVAPDF】獲取200頁面試題滴劲!
5萬人關(guān)注的大數(shù)據(jù)成神之路攻晒,不來了解一下嗎?
5萬人關(guān)注的大數(shù)據(jù)成神之路班挖,真的不來了解一下嗎鲁捏?
5萬人關(guān)注的大數(shù)據(jù)成神之路,確定真的不來了解一下嗎萧芙?
歡迎您關(guān)注《大數(shù)據(jù)成神之路》
[圖片上傳失敗...(image-1115b7-1593177454094)])