什么时数据倾斜
由于数据分布不均匀,造成数据大量的集中到一起,造成数据热点。Hdfs是分布式存储的,很有可能数据集中在一个节点上面。造成有的节点一直busy,有的节点很free。
hadoop框架的特性
a.不怕数据大,怕数据倾斜,数据再大,只要多节点并发运行都可以解决的。如果发生了数据倾斜,会造成其他节点都忙完了,还有节点一直在busy,导致结果一直出不来,都在等busy的节点结束。
b.Jobs数比较多的作业运行效率相对比较低,如子查询比较多
c.sun,count,max,min等聚集函数,通常不会造成数据倾斜
容易数据倾斜的情况
#a.第一种情况
join 其中一个表较小,但是Key集中,比如很多1,这样按照hash跟reduce数量取模分区的时候,造成全是1的分布在一个reduce上面干活,这样的结果是某些个节点上的数据远远高于平均
#b.第二种情况
join 大表与大表,但是分桶的判断字段0值或空值过多(就是分区不合理导致的,比如西藏人少,上海人多,按照地区来分区就会数据倾斜),这些空值由一个reduce处理,非常慢。
#c.第三种group by 不和聚集函数搭配使用的时候
group by 维度过小,某值的数量过多,处理某值的reduce非常耗时(按照我们班级为例,男女生分组,男生多,女生少)
#d.第四种(这个方法尽量不用)
count (distinct)某特殊值过多,处理特殊值的reduce耗时。因为count(distinct)是按照group by 分组的,按照distinct字段排序的。
产生数据倾斜的原因
1.key分布不均匀
2.业务数据本身的特性
3.建表考虑不周全
4.某些HQL语句本身就存在数据倾斜
业务场景如何解决数据倾斜
#1.空值产生的数据倾斜
#场景说明:
在日志中,常会由信息丢失的问题:比如日志中的user_id,如果取其中的user_id和用户表的user_id关联,就会碰到数据倾斜问题。丢失的信息user_id会是空,这样就会分到同一个区,造成某些reduce的压力很大。
#解决方案一:user_id为空的不参与关联
select * from log a join user b on a.user is not null and a.user_id=b.user_id
union all
select * from log c where c.user_id is null
#解决方案二:赋予空值新的key值
select * from log a join user b on case when a.user_id is null then concat('hive',rand()) else a.user_id end =b.user_id
#总结:方案二比方案一好,减少了IO。方案二把空值的key变成一个字符串加一个随机数,就把造成数据倾斜的数据分到不同的reduce上面解决数据倾斜的问题。
#2.不同数据类型关联产生数据倾斜(设计表不合理)
#场景说明:
设计表的时候,用户表的user_id为int类型,log表中的user_id既有int也有string(也有可能都是string),当两个表user_id进行join的时候,默认hash操作会按照int类型的id进行匹配,这样会导致所有的string类型会分到一个分区。
#解决方案(类型转换)
select * from user a join lob b on b.user_id=cast(a.user_id as string)
#3.大小表关联查询产生数据倾斜
默认会走Mapjoin,老版本的hive需要自己开启设置,1.1版的Hive不需要
默认小表是25M。可以自己调大一点
set hive.mapjoin.smalltable.filesize=250000000
#4.大表大表关联产生数据倾斜
#方案: 把大表切分成小表,然后Mapjoin
使用mapjoin解决小表(25M)关联大表的数据倾斜问题,这个方法使用的频率非常高,但是如果小表还是很大,大到mapjoin会出现异常,这时要特别处理。
#业务场景
users表有600W+的记录,把users分发到所有的Map上占内存,而且mapjoin也不支持这么大的小表。如果用普通的Join又会碰到数据倾斜的问题
with
t1 as (select * from (select distinct user_id from log)c jaoin users d on c.user_id=d.user_id) --这个就等于把表变小
select * from log a join t1 on a.user_id=t1.user_id
假如,log里user_id只有一百万个(很多用户注册了不一定有行为日志),这就又回到了mapjoin。每日的会员的uv不会太多,有交易的会员不会太多,有点击的会员不会太多等等。所以这个方法能解决很多场景下的数据倾斜。