1、数据倾斜的表现
数据倾斜是由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点的现象。
主要表现:任务进度长时间维持在 99%或者 100%的附近,查看任务监控页面,发现只有少量 reduce 子任务未完成,因为其处理的数据量和其他的 reduce 差异过大。 单一 reduce 处理的记录数和平均记录数相差太大,通常达到好几倍之多,最长时间远大于平均时长。
2、出现的原因:
其实数据倾斜这个问题,在MapReduce编程模型中十分常见,根本原因就是大量相同的key被分配到一个reduce里,造成一个reduce任务处理不过来,但是其他的reduce任务没有数据可以处理。下面罗列一下常见的数据倾斜有哪些原因 :
1)数据类型不一致造成数据倾斜
情形:
比如用户表users中user_id字段为int,logs表中user_id字段string类型。当按照user_id进行两个表的Join操作时。解决方式:把数字类型转换成字符串类型
select * from users a
left outer join logs b
on a.usr_id = cast(b.user_id as int)
2)数据中出现大量的null值
统计 a-p 放入一个文件 100
q-z 另一个文件中 200
其他类型 放入第三个文件中 100万
分为两种情况,第一种情况,null值是异常值,就不应该出现,比如 userId 出现 null
比如一个员工表中,员工的姓名为null,一个银行系统表中没有银行卡号null.
对于异常值如果不需要的话,最好是提前在where条件里过滤掉,这样可以使计算量大大减少。
-- 处理方式是在left join 前直接通过where条件过滤掉
select n.* from (select * from nullidtable where id is not null) n
left join bigtable o on n.id = o.id;
第二种情况,出现null的数据不是异常数据,需要保留。【麻烦了】
虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。
-- 设置reducer数量:
set mapreduce.job.reduces = 5;
-- 解决方案是给null值产生随机数
本来是真么写的,出现倾斜
-- 设置reducer数量:
set mapreduce.job.reduces = 5;
-- 解决方案是给null值产生随机数
select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id;
select n.* from nullidtable n full join bigtable o on n.id = o.id;
修改:
-- 设置reducer数量:
set mapreduce.job.reduces = 5;
-- 解决方案是给null值产生随机数
hive (default)> select rand();
OK
_c0
0.7662188287998238select n.* from nullidtable n full join bigtable o on n.id = o.id;
select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id;以上两条数据查询的结果是一样的。
思考:
本来 n id = null 不可能等于 o.id ,因为 o.id(正整数 1 2 3 4 5 1000等)
3)单表group by 出现数据倾斜
导致数据倾斜的主要原因在于按照 Key 分组以后,少量的任务负责绝大部分数据
的计算,也就是说产生数据倾斜的 HQL 中一定存在分组操作,那么从 HQL 的角度,我们可以将数据倾斜分为单表携带了 GroupBy 字段的查询和两表(或者多表)Join 的查询。
解决方案:
第一种方案:使用参数优化
当任务中存在group by操作同时聚合函数为count或者sum,可以设置参数来处理数据倾斜的问题。
并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。
突然让我们想起了Combine操作,就是运行在map端的reduce.
1、是否在Map端进行聚合,默认为True
hive(default)> set hive.map.aggr = true
2、在Map端进行聚合操作的条目数目
hive(default)> set hive.groupby.mapaggr.checkinterval = 100000
3、有数据倾斜的时候进行负载均衡(默认是false)
hive(default)> set hive.groupby.skewindata = true
4、当开启数据负载均衡时,生成的查询计划会有两个MRJob。
第一个MRJob中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;
第二个MRJob再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作.
select sex,count(sex) from student group by sex;
第二种方案:增加Reduce数量
当数据中的多个key同时导致数据倾斜,可以通过增加reduce的数量解决数据倾斜问题
1)调整Reduce个数方法1:
① 每个Reduce处理的数据量默认是256MB
hive(default)> set hive.exec.reducers.bytes.per.reducer=256000000
② 每个任务最大的reduce数,默认为1009
hive(default)> set hive.exec.reducers.max=1009
③ 计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
2)调整Reduce个数方法2:
通过参数配置的方式(三种)直接指定reduce的个数,参数mapreduce.job.reduces。
hive(default)> set mapreduce.job.reduces = 15;
4)多表join出现数据倾斜
解决方案一:使用参数解决
在编写 Join 查询语句时,如果确定是由于 join 出现的数据倾斜,那么请做如下设置:
select * from emp a join dept b on a.deptno = b.detpno;
#join的键对应的记录条数超过这个值则会进行拆分,值根据具体数据量设置
set hive.skewjoin.key=100000;
# 如果是join过程出现倾斜应该设置为true
set hive.optimize.skewjoin=false;
如果开启了,在Join过程中Hive会将计数超过阈值hive.skewjoin.key(默认100000)的倾斜key对应的行临时写进文件中,然后再启动另一个job做map join生成结果。
通过 hive.skewjoin.mapjoin.map.tasks参数还可以控制第二个job的mapper数量,默认10000。
set hive.skewjoin.mapjoin.map.tasks=10000;
第二种解决方案:大小表join
使用大表打散小表扩容: