hive join 数据倾斜 真实案例
共 2450字,需浏览 5分钟
·
2020-12-07 14:07
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
很简单的一个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
结果为:
192928 5828529
2000000000496592833 2406289
18000 1706031
4000288 1386324
2000000003624295444 1201178
2000000001720892923 1029475
2000000002292880478 991299
2000000000736661289 881954
2000000000740899183 873487
2000000000575115116 803250
对于有上亿数据的一个表来说,这数据也算不上倾斜多厉害嘛。最多的一个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
结果也很快出来
192928 383412
18000 60318
617279581 23028
51010262 4643
4000286 3528
2000000000575115116 3218
1366173280 3012
4212339 2972
2000000002025620390 2704
2000000001312577574 2622
这数据倾斜,也不是特别严重嘛。
不过再把这两个结果一对比,尼玛恍然大悟。两个表里最多的一个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)
将此代码重新提交,5min时间,job跑完收工!
--end--
扫描下方二维码 添加好友,备注【交流】 可私聊交流,也可进资源丰富学习群