Hive或者MR處理數據,不怕數據量大,就怕傾斜。hive裏大表join的時候,數據傾斜就是個很頭疼的問題。本博主就遇到了一個真實案例,特意記錄下來,有需要的同學可以參考
1.查了5個小時還沒結束的sql語句
set mapred.reduce.tasks = 30;
insert overwrite directory 'xxx'
select
cus.idA,cus.name,addr.bb from tableA as cus
join tableB as addr
on cus.idA = addr.idB
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
很簡單的一個hql語句,優化的空間也不是很大(例子中的addr數據量比cus小,應該講addr放在前面驅動join)。tableA的量級爲億級,tableB的量級爲幾百萬級別。就這麼一個簡單的sql,尼瑪從上午十點半開始跑,跑到下午三點半還沒有跑完。實在受不了了,kill掉了。
2.初步分析
首先上個查詢過程中的圖
看到這種情況,稍微有點經驗的同學第一反應肯定就是:臥槽,這尼瑪肯定是數據傾斜了。沒錯,map早就完工了,reduce階段一直卡在99%,而且cumulative cpu的時間還一直在增長,說明整個job還在後臺跑着。這種情況下,99%的可能性就是數據發生了傾斜,整個查詢任務都在等某個節點完成。。。
3.分析那部分數據產生了傾斜
問題既然已經定位了,那接下來就是需要解決問題了。正好不巧的是,集羣這幾天還出了一些狀況。so,首先爲了確認到底是集羣本身的問題,還是代碼的問題,先找了另外兩個表,都是億級數據。這兩個表不存在數據傾斜的情況,join一把試了試,兩分鐘之內結果就出來了。萬幸,說明這會集羣已經沒有問題了,還是查查數據跟代碼吧。
代碼本身很簡單,那就沿着數據傾斜的方向查查吧。因爲上面的兩個表是根據id關聯的,那如果傾斜的話,肯定就是id傾斜了哇。
set mapred.reduce.tasks = 5;
select idA,count(*) as num
from tableA
group by idA
distribute by idA
sort by num desc limit 10
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
結果爲:
192928 5828529
2000000000496592833 2406289
18000 1706031
4000288 1386324
2000000003624295444 1201178
2000000001720892923 1029475
2000000002292880478 991299
2000000000736661289 881954
2000000000740899183 873487
2000000000575115116 803250
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
對於有上億數據的一個表來說,這數據也算不上傾斜多厲害嘛。最多的一個key也就五百多萬不到六百萬。好吧,先不管了,再查一把另外一個表
set mapred.reduce.tasks = 5;
select idB,count(*) as num
from tableB
group by idB
distribute by idB
sort by num desc limit 10
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
結果也很快出來
192928 383412
18000 60318
617279581 23028
51010262 4643
4000286 3528
2000000000575115116 3218
1366173280 3012
4212339 2972
2000000002025620390 2704
2000000001312577574 2622
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
這數據傾斜,也不是特別嚴重嘛。
不過再把這兩個結果一對比,尼瑪恍然大悟。兩個表裏最多的一個key都是192928,一個出現了將近600萬次,一個出現了將近40萬次。這兩個表再一join,尼瑪這一個key就是600萬*40萬的計算量。最要命的是,這計算量都分配給了一個節點。我數學不太好,600萬*40萬是多少,跪求數學好的同學幫忙計算一下。不過根據經驗來看的話,別說5個小時,再添個0也未必能算得完。。。
4.如何解決
既然找到了數據傾斜的位置,那解決起來也就好辦了。因爲本博主的真正需求並不是真正要算兩個表的笛卡爾積(估計實際中也極少有真正的需求算600萬*40萬數據的笛卡爾積。如果有,那畫面太美我不敢看),所以最easy的解決方案,就是將這些key給過濾掉完事:
set mapred.reduce.tasks = 30;
insert overwrite directory 'xxx'
select
cus.idA,cus.name,addr.bb from tableA as cus
join tableB as addr
on cus.idA = addr.idB
where cus.idA not in (192928,2000000000496592833,18000,4000288,2000000003624295444,2000000001720892923,2000000002292880478,2000000000736661289,2000000000740899183,2000000000575115116,617279581,51010262,4000286,1366173280,2000000002025620390,2000000001312577574)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
將此代碼重新提交,5min時間,job跑完收工!