數(shù)據(jù)傾斜是由于某個(gè)task被分配過多數(shù)據(jù)斜做,而比其他task需要更多的執(zhí)行時(shí)間(如幾十倍臀叙,幾百倍),導(dǎo)致其他task執(zhí)行完進(jìn)入漫長等待的一種現(xiàn)象锅纺。
數(shù)據(jù)傾斜只會(huì)發(fā)生在多對多或一對多的數(shù)據(jù)分發(fā)的過程中攀涵,如spakr的shuffle操作中铣耘,在MapReduce中的reduce階段,
常見的算子類型為:join以故,group by 和窗口函數(shù)如row_number 蜗细。
這是因?yàn)檫@些算子會(huì)進(jìn)行shuffle操作,產(chǎn)生一個(gè)key值怒详,如group by的字段炉媒,join的on字段,
為了利用多臺(tái)機(jī)器的并發(fā)能力昆烁,會(huì)按這個(gè)key值取數(shù)范圍進(jìn)行均衡的分發(fā)吊骤,每臺(tái)機(jī)器盡量分到相同長度的取值范圍的key,
然后將這些有key值的數(shù)據(jù)的數(shù)據(jù)傳輸過去静尼。
這時(shí)如果某個(gè)key范圍內(nèi)的數(shù)據(jù)量大大多于其他范圍的數(shù)據(jù)量白粉,就會(huì)發(fā)生數(shù)據(jù)傾斜。
解決辦法:
解決數(shù)據(jù)傾斜的思路在于鼠渺,先找到產(chǎn)生數(shù)據(jù)傾斜的算子操作鸭巴,然后針對具體的算子,解決它單個(gè)key范圍被分到過多的數(shù)據(jù)的問題拦盹,
按key的類型鹃祖,由簡便到復(fù)雜依次有以下幾種解決思路:
1.直接消滅傾斜的key。
2.直接避免shuffle操作普舆,沒有了shuffle操作也就沒有了數(shù)據(jù)傾斜
3.通過增多task的數(shù)量恬口,減小單個(gè)task內(nèi)的數(shù)據(jù)量校读,這個(gè)方法適用于某個(gè)key范圍的數(shù)據(jù)多的情況。
4.通過特殊處理key值祖能,減小單個(gè)task內(nèi)的數(shù)據(jù)量地熄,這個(gè)方法適用于某些特定的key值的數(shù)據(jù)過多的情況
第一個(gè)解決思路比較簡單,找到傾斜的key芯杀,直接過濾掉。就沒有傾斜問題了雅潭。這種操作的適用范圍很窄揭厚。比如一些空字符串,一些缺省值等等扶供,本身在業(yè)務(wù)上能接受它們不參與操作筛圆。
如果發(fā)現(xiàn)造成傾斜的key是這些,就可以直接過濾椿浓,非常簡單粗暴太援,性價(jià)比最高。
如果該key不能被過濾扳碍,就考慮能否將shuffle操作避免掉提岔。
比如join的時(shí)候使用廣播的方式,將其中一張表廣播到所有的機(jī)器節(jié)點(diǎn)上笋敞,這樣一個(gè)shuffle操作就變成了一個(gè)map操作碱蒙。
廣播的方式(map join)適用于join的時(shí)候某一張表的數(shù)據(jù)量比較小的時(shí)候,如果兩張表都很大夯巷,則不適用這種方式赛惩。
如果不能避免shuffle操作也不能過濾傾斜的key值,那么我們就要從key值的類型入手趁餐,如果傾斜的key值是連續(xù)的喷兼,不是由單個(gè)key值引起的,就可以增大task的數(shù)量后雷,
比如季惯,修改shuffle產(chǎn)生的partition參數(shù)為更大,就可以使同一個(gè)范圍內(nèi)的key值分到不同機(jī)器上喷面,
或者使key值重新排列星瘾,倒排或者其他方式,使他們不再連續(xù)惧辈,分配到不同的機(jī)器上琳状,就可以防止傾斜。
上述3個(gè)操作都比較簡單高效盒齿,但是應(yīng)用的場景有限念逞,如果該key不能被過濾困食,也不能避免shuffle,而且是1個(gè)到多個(gè)不連續(xù)的key引起的翎承,就需要做比較復(fù)雜的操作了硕盹。
如果是group by,就可以用兩階段聚合法叨咖,
將group by a 改成 group by a,b? 瘩例,然后再group by a
或者增加一個(gè)隨機(jī)數(shù)x,將a通過concat(x,a)改成b,將group by a 改成 group by b, 然后再聚合一次去掉x后的b甸各,group by substr(b,length(x))?
如果是join操作垛贤,就需要分開join,將傾斜的數(shù)據(jù)和不傾斜的數(shù)據(jù)分成兩部分趣倾。
然后兩站表不傾斜的部分join得到第一張表聘惦。
傾斜的數(shù)據(jù),第一張較大的表:增加一個(gè)隨機(jī)數(shù)1-x儒恋,隨機(jī)數(shù)取決于你想把數(shù)據(jù)切成幾份善绎。
得到 concat(x,a).?
另一張較小的表將每一行復(fù)制到x份(總共增加x-1份),然后按順序標(biāo)上序號(hào)1到x诫尽,如下所示:
源數(shù)據(jù)禀酱,傾斜的key值為a和b,
大表:aaaaa bbbbb?
小表:aaaa bbbb
原來的join最后得到40條數(shù)據(jù). 每個(gè)key分到20條
處理過key的表牧嫉,
大表:1a 2a 2a 1a 2a 1b 2b 3b 3b 2b? (增加一個(gè)隨機(jī)數(shù)前綴1-3)
小表:
1a 2a 3a 1a 2a 3a 1a 2a 3a 1a 2a 3a 這n條數(shù)據(jù)都按順序附加一個(gè)1~x的前綴
1b 2b 3b 1b 2b 3b 1b 2b 3b 1b 2b 3b
生成40條數(shù)據(jù)比勉,每個(gè)key平均分到6.66條.
6.66條的計(jì)算公式是5/3*4,? 5是大表的key的條數(shù),有5個(gè)驹止,增加隨機(jī)數(shù)之后浩聋,被分成了3份,得到了5/3 條臊恋,小表雖然也加了隨機(jī)數(shù)但是復(fù)制了x份衣洁,
所以小表的key還是4個(gè),所以是:5/3*4
最后將傾斜部分的數(shù)據(jù)和不傾斜的部分的數(shù)據(jù)分別join之后再union起來就可以了抖仅。
當(dāng)然坊夫,解決數(shù)據(jù)傾斜的不止這些方法,這些方法只是常用的撤卢,本質(zhì)還是打散集中在某臺(tái)機(jī)器环凿,某個(gè)task的的數(shù)據(jù)量。只要能達(dá)到這個(gè)目的放吩,就可以智听。