数据倾斜就是数据的分布不平衡,有些地方数据多,有些地方数据少,有些地方数据早早地处理完了,有些地方数据迟迟没有处理完成,造成整个处理流程迟迟没有结束。

Hive的数据倾斜本质上是MapReduce的数据倾斜。数据倾斜发生在shuffle的过程中,指的是上游的数据经过hash送到不同的reduce中,有些reduce task中的数据少,处理很快完成,但是有些reduce task中的数据多,花了很长时间才处理完成,造成整个处理流程花费的时间很长。

当我们发现所有的map task全部完成,并且99%的reduce task完成,只剩下一个或者少数几个reduce task一直在执行,这种情况下一般都是发生了数据倾斜。

产生数据倾斜的原因:

  • (1)key选取不合理,key分布不均衡,某些key太集中。
  • (2)业务数据本身的问题,某些数据比较集中

但是根本原因都是key的分布不均衡。对应的方案要么是从源头解决(不让数据分区,直接在map端搞定),要么就是在分区的时候将无效的可以过滤(清洗)掉,或者想办法将这些key打乱,让它们进入到不同的reduce中。

常见的解决方案:

一. 参数设置

(1)设置hive.map.aggr=true

开启map端部部分聚合功能,就是key相同的记录归到一起,减少数据量,这样就可以相对地减少进入reduce的数据量,在一定程度上可以提高性能。

(2)设置hive.groupby.skewindata=true

如果发生了数据倾斜,就通过它来负载均衡。当选项设定了true,生成的查询计划会有两个mr job。第一个mr job中,map的输出结果集会随机分布到reduce中,每个reduce做部分聚合,并输出结果,这样处理结果是相同key有可能被发送到不同的reduce种,从而达到负载均衡的目的。第二个mr job再根据处理的数据结果按照key分布到reduce中,按照key值进行hash,进行最后的聚合。

但是应用场景有限,skewindata配置真正发生作用,只会在以下三种情况,能够将一个job转化为2个job:

select count distinct ... from ...
select a,count(*) from ... group by a
select count(*),count(distinct..) from ...

二. 从数据角度出发

1、过滤大表中的有效数据,使用map join

如果大表中的数据只有极少数是有用数据,那么可以将它们先取出来,得到的结果是一张小表,那么就可以使用map join来避免数据倾斜。

2、造成数据倾斜的数据是无效的

  • 直接过滤:造成业务数据倾斜的原因是key为null或者无效。
  • 检测到key加上一个新的随机值。因为有效的数据的key没有这种形式的,所以他也无法关联,不影响最后的结果。

3、造成数据倾斜的数据是有效的

  • 先过滤再加上。比如统计某一个页面访问次数最多的id,可以先排序,把最多的id过滤掉,然后剩下的再计算或者分组计算。最后加上原来的结果。
  • 加盐(比如加上随机后缀)打乱进入到不同的reduce中,然后,再去掉后缀进行局部聚合,最后再来进行全局的聚合。效果非常好,但是适用于聚合类的操作