一、现象
map/reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜。
二、具体情况及解决
1. join的key值发生倾斜
1) key值包含很多空值或是异常值
如果需要这些值,可以给这些值赋一些随机值:
select userid ,name from user_info a join ( select case when userid is null then cast ( rand (47 )*100000 as i nt ) else userid from user_read_log ) b on a .userid = b .userid
如果不需要,则要提前过滤掉:
select userid ,name from user_info a join ( select userid from user_read_log where userid is not null ) b on a .userid = b .userid
2) key值都是有效值
设置每个节点的reducer,默认处理1G大小的数据:
set hive.exec.reducers.bytes.per.reducer = 1000000000;
如果你的join操作也产生了数据倾斜,那么你可以在hive中设定:
set hive.optimize.skewjoin = true; set hive.skewjoin.key = skew_key_threshold (default = 100000);
hive 在运行的时候没有办法判断哪个key会产生多大的倾斜,所以使用这个参数控制倾斜的阈值,如果超过这个值,新的值会发送给那些还没有达到的reduce, 一般可以设置成(处理的总记录数/reduce个数)的2-4倍。
如果你不知道设置多少,可以就按官方默认的1个reduce只处理1G的算法,那么 skew_key_threshold = 1G/平均行长, 或者默认直接设成250000000 (差不多算平均行长4个字节)
2. reduce数太少
直接设置reduce任务个数:
set mapred.reduce.tasks=800;
默认是先设置hive.exec.reducers.bytes.per.reducer这个参数,设置了后hive会自动计算reduce的个数,因此两个参数一般不同时使用。
3. 对于group by 产生倾斜的问题
1) 开启map端combiner
set hive.map.aggr=true;
不过如果map各条数据基本上不一样,聚合没什么意义,这样,做combiner反而画蛇添足。
还有另外两个相关参数:
hive.groupby.mapaggr.checkinterval = 100000 (默认) hive.map.aggr.hash.min.reduction=0.5(默认)
两个参数的意思是:预先取100000条数据聚合,如果聚合后的条数/100000>0.5,则不再聚合。
2) 开启group by查询数据倾斜优化
set hive.groupby.skewindata=true;
生成的查询计划会有两个 MR Job。
第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的。
第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
4. 小表与大表关联
可以通过mapjoin来优化,将小表刷入内存中:
set hive.auto.convert.join = true;
设置刷入内存表的大小(字节):
set hive.mapjoin.smalltable.filesize = 2500000;
三、参考
3. Hive数据倾斜
(完)