easy-algorithm-interview-an.../bigdata/hive/hive join 数据倾斜 真实案例.md

4.3 KiB
Raw Blame History

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跑完收工