零、回顾mr
以经典WordCount为例
由图中可以看到,在shuffle的时候,必须将各个节点相同的key拉取到某一个节点进行task的处理,比如:join\group by,如果某个key对应的数据量非常大,那么必然这个key对应的数据进行处理的时候就会产生数据倾斜。
凡是涉及到shuffle的操作,都有可能出现数据倾斜
一、现象
任务进度长时间维持在99%(或100%)。
查看任务监控页面,绝大多数task执行得都非常快,但个别task执行极慢。因为其处理的数据量和其他reduce差异过大。
比如,总共有1000个task,997个task都在1分钟之内执行完了,但是剩余两三个task却要一两个小时。10个人干活,一个人干90%,9个人在边上看着,对于团队来说效率可不慢吗~~~木桶定理
某天突然报出OOM(内存溢出)异常。
观察异常栈,是我们写的业务代码造成的。突然让干几倍的活,可不给逼疯了~~~
二、产生原因
本质:map 输出数据按 key 的Hash 分配到 reduce 中,由于以下原因造成的 reduce 上的数据量差异过⼤。
- key分布不均匀
- 业务数据本身特性
- 建表考虑不周
- 某些sql语句本身就有数据倾斜
三、操作:
凡是涉及到shuffle的操作,都有可能出现数据倾斜,下面的可能不全哦~~~
- join
- 一个表小但key集中
分发到某一个或几个Reduce上的数据远高于平均值
- 都是大表,但空值过多
这些空值都由一个reduce处理,非常慢
- 一个表小但key集中
- group by
- 维度过小,处理某值的reduce非常慢
处理某值的reduce非常耗时
- 维度过小,处理某值的reduce非常慢
- count distinct
- 特殊值过多
处理此特殊值的reduce耗时
- 特殊值过多
四、解决
本质是如何将数据均匀分配到各个reduce中
参数调节
- hive.map.aggr=true
map端聚合,相当于combiner
- hive.groupby.skewindata=true
有数据倾斜的时候进行负载均衡,两个MR job,第一个随机分配map结果,从而达到负载均衡的目的,局部聚合;第二个按照 Group By Key 分布到 Reduce 中,最终聚合
sql优化
- 减少数据量,列裁剪和fillter
不需要的列就不要了,以达到两表做join的时候,数据量相对变小的效果
SELECT a.id
FROM bigtable a
LEFT JOIN ori b ON a.id = b.id
WHERE b.id <= 10;
--改写成
SELECT a.id
FROM ori a
LEFT JOIN bigtable b ON (a.id <= 10 AND a.id = b.id);
--或者直接改写成子查询
SELECT a.id
FROM bigtable a
RIGHT JOIN (SELECT id
FROM ori
WHERE id <= 10
) b
ON a.id = b.id;
- 大小表join,小表先进内存,在map端完成reduce
(新的版本当中已经没有区别了,旧的版本当中需要使用小表)
- 大大表join,
空值变字符串加随机数
,分散到不同reduce,null关联不上,所以不影响最终结果
select *
from log a
left join users b
on case when a.user_id is null
then concat('hive',rand())
else a.user_id
end = b.user_id
- count(distinct)大量相同值
采用sum() group by的方式来替换count(distinct)完成计算
将值为空的情况单独处理
,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1;如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。
select *
from log a
join users b
on a.user_id is not null and a.user_id=b.user_id
union all
select * from log a where a.user_id is null;
- group by维度过小:
选择一个具有分散的字段 b,按照a,b聚合,得到一个比较小的中间结果集 ,再group by a
select a,count(distinct b) as c from tb_name group by a;
--改写成
select a,count(*) as c
from (select a,b
from tb_name
group by a,b
)
group by a;
- 特殊情况特殊处理:
- 在业务逻辑优化效果的不大情况下,有些时候是可以将倾斜的数据单独拿出来处理。最后union回去。
五、扩展
不同数据类型关联产生的倾斜问题
- 问题:不同数据类型 id 的关联会产生数据倾斜问题。
- 一张表 s8 的日志,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。 s8 的日志中有 32 为字符串商品 id,也有数值商品 id,日志中类型是 string 的,但商品中的 数值 id 是 bigint 的。猜想问题的原因是把 s8 的商品 id 转成数值 id 做 hash 来分配 Reduce, 所以
字符串 id 的 s8 日志,都到一个 Reduce 上了
,解决的方法验证了这个猜测。 - 解决方法:把数据类型转换成字符串类型
SELECT *
FROM s8_log a
LEFT OUTER JOIN r_auction_auctions b
ON a.auction_id=CAST(b.auction_id AS STRING)