解决hive中数据倾斜问题

  平常工作中我们在使用hive处理业务问题的时候不可避免的会遇到数据倾斜的问题,数据倾斜的本质就是key的分布不均匀,导致分到不同reduce上的数据量差距或大或小,当数据量差距过大的时候就造成了数据倾斜,使得某一个reduce的负担过大,导致任务迟迟不能完成。

主要原因

1.key分布不均匀。
2. map端数据倾斜,输入文件过多,并且大小不统一。
3. reduce端数据倾斜,分区器存在问题。
4.业务数据本身特征。

解决方案

1.调节hive中的参数
如下所示:

set hive.map.aggr=true;
set hive.groupby.skewindata=true;

hive.map.aggr=true这个参数是用来设置在map端进行部分聚合的,相当于Combiner
hive.groupby.skewindata=true这个参数设置为true在发生数据倾斜的时候,会生成两个MR JOB,第一个MR JOB会先将key进行随机分布,尽量均匀的分布在不同的reduce中,每个reduce中先将数据进行部分聚合,然后再由第二个MR JOB处理数据,这个时候数据已经是经过部分聚合的结果数据,会将相同key的数据都分到一个reduce当中,这个时候再进行统一的group by key处理基本上就会避免发生某个reduce压力过大的情况。

2.优化mapreduce
如下所示:

set hive.merge.mapfiles=true;
set hive.mapred.map.tasks=number;

set hive.merge.mapfiles=true是用来处理小文件过多,给map造成了很大的压力的时候通过这个参数来进行小文件的合并,或者也可以通过这个命令set hive.mapred.map.tasks=number来调节mapper的数量,由多个mapper来平分map端的压力。

set hive.mapred.reduce.tasks=number;

set hive.mapred.reduce.tasks=number通过这个命令来调节reduce的数量,这个一般只是适合某些业务场景的数据倾斜问题,比如商品类型中有80种数据量比较大的不同分类都在一个reduce中进行聚合,这个时候增加reduce的个数,在进行hash分区的时候可能就会将这80种商品类型分发到不同的reduce当中,增加reduce的个数来处理数据倾斜的问题还是具备很强的局限性的,而且不一定能够起作用。

3.sql优化
3.1 null值问题产生的数据倾斜
null值问题产生的数据倾斜,这在实际业务中是常见的问题,比如说流量域中的用户行为日志数据,有时就会发生user_id数据丢失的问题,这个时候user_id就会产生大量的空值,这个时候如果和用户信息表进行关联就会发生数据倾斜的问题,解决方式如下所示:

-- 1.这种情况在join的时候直接过滤空值,最后给union all上
select 
 *
from a
join
b
on
a.id is not null and a.id = b.id
union all
select
 * 
from
a 
where a.id is null;
 
-- 2.给空值字段取一个字符串常量+随机数
select 
 *
from a 
left outer join 
b 
on
case 
when a.id is null 
then concat('常量字段',rand()) 
else a.id 
end = b.id

第二种方法和第一种方法相比要更好一些,因为 IO次数 少了,作业数也少了,第一种方法中,用户行为日志表读了两次,jobs肯定是 2,第二种方法是 1。这个优化适合无效 id产生的数据倾斜,把空值的key变成一个字符串加上一个随机数,就能把造成数据倾斜的 数据分到不同的reduce上解决数据倾斜的问题。使本身为 null 的所有记录不会拥挤在同一个 reduceTask了,会由于有替代的 随机字符串值,而分散到了多个 reduceTask中了,由于null值关联不上,处理后并不影响最终结果。

3.2 小表关联大表
在使用 hvie处理数据的时候,涉及到小表和大表关联的时候,这个问题一般是比较好解决的,我们只需要将小表先塞进内存,类似于Spark中的广播变量,实现方式如下所示:

set hive.auto.convert.join=true; //设置 MapJoin 优化自动开启
set hive.mapjoin.smalltable.filesize=25000000 //可以根据情况设定具体值

3.2 大表关联大表
1.在大表和大表关联的时候设置map join就已经不起作用了,因为不会将任何一张大表广播到map端,防止大表对于内存的压力过大导致内存浪费,这个时候我们可以先将两张大表中的无用的列和行进行过滤,然后再进行关联,如果无用的数据比较多,这样做就可以很大程度上减轻节点的压力,避免数据倾斜的问题。

2.如果两张大表确实有这么多的数据要进行关联我们可以尝试如下方法:

set hive.optimize.skewjoin = true; 
set hive.skewjoin.key = skew_key_threshold (default = 100000

hive 在运行的时候没有办法判断哪个key 会产生多大的倾斜,所以使用这个参数控制倾斜的阈值,如果超过这个值,新的值会发送给那些还没有达到的reduce

猜你喜欢

转载自blog.csdn.net/AnameJL/article/details/113205453