Hive 数据倾斜解决方案:
1.调节参数
hive.map.aggr=true Map端部分聚合,相当于combiner
hive.groupby.skewindata=true
有数据倾斜的时候进行负载均衡,当选项设定为true,生成的查询计划会有两个mr job,
第一个job中,map的输出结果集合会随机分不到reduce中,每个reduce做部分聚合操作,
并输出结果,这样的处理结果是相同的groupByKey会分到不同的reduce中,从而达到敷在君更的目的;
第二个job再根据预处理的数据结果按照GroupByKey分不到redcue,最终完成聚合
2. 小表和大表进行join操作
使用map join让小的维度表(1000条以下的记录数)先进内存[distributedCache],在map端完成reduce
3.1 空值产生的数据倾斜
赋予空值新的key值
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
好处:这个方法只有一个job,把空值的key变成了字符串加上随机数,就能把倾斜的数据分到不同的reduce上,
解决数据倾斜问题。
3.2 不同数据类型关联产生数据倾斜
比如 用户表user_id为int类型,log表中的user_id 字段既有int也有string类型,
当按照user_id进行两个表的join操作时,默认的hash操作会按照int类型的id来进行分配,
这样就会导致所有string类型的id记录都分配到一个reducer中
解决:把数字类型转换成字符串类型
select *
from
users a
left outer join logs b
on
a.user_id = cast(b.user_id as string)
3.3 users表有600w+的记录,把users分发到所有的map也是不小的开销,而且map join不支持这么大的小表,
如果用普通的join,又会碰到数据倾斜的问题
解决:
select * from log a
left outer join
(
select d.* from (select distinct user_id from log) c
join users d
on c.user_id = d.user_id
) x
on a.user_id = x.user_id;
spark解决数据倾斜:
1.增加并行度,也就是增加task的个数,可以缓解数据倾斜 这样可以将分配到统一task上的key散开,
2.自定义 partition 默认是 HashPartition,这样可以将不同的key分配到多个task上,
但是也只是缓解,而且也不灵活,不能解决同一个key数据量很好的场景
3.将reduce端join变成map端join -- broadcast
优势:
避免了shuffle,彻底解除了数据倾斜
劣势:
要求join的一侧数据集合足够小,适用于join,不适用于聚合
4.在数据倾斜的key前面加前缀,让这个key分不到不同的task中
将有数据倾斜的RDD中倾斜Key对应的数据集单独抽取出来加上随机前缀,
另外一个RDD每条数据分别与随机前缀结合形成新的RDD(相当于将其数据增到到原来的N 倍,N即为随机前缀的总个数),然后将二者Join并去掉前缀。然后将不包含倾斜Key的剩余数据进行Join。
最后将两次Join的结果集通过union合并,即可得到全部Join结果。