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  58285292000000000496592833 240628918000   17060314000288 13863242000000003624295444 12011782000000001720892923 10294752000000002292880478 9912992000000000736661289 8819542000000000740899183 8734872000000000575115116 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  38341218000   60318617279581   2302851010262    46434000286 35282000000000575115116 32181366173280  30124212339 29722000000002025620390 27042000000001312577574 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--


扫描下方二维码
添加好友,备注【交流
可私聊交流,也可进资源丰富学习群

浏览 9
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报