数据倾斜(四):Hive是如何解决数据倾斜的

六、Hive解决数据倾斜具体方法

6.1 场景

6.1.1 group by

注:group by 优于distinct group
情形:group by 维度过小,某值的数量过多
后果:处理某值的reduce非常耗时
解决方式:采用sum() group by的方式来替换count(distinct)完成计算。

6.1.2 count(distinct)

count(distinct xx)
情形:某特殊值过多
后果:处理此特殊值的reduce耗时;只有一个reduce任务
解决方式:count distinct时,将值为空的情况单独处理,比如可以直接过滤空值的行,在最后结果中加1。如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。

6.1.3 join

情形1:小表与大表join,但较小表key集中
后果:shuffle分发到某一个或几个Reducer上的数据量远高于平均值。想象极端情况,小表的join列全部为一个值,那么shuffle后全部到一个Reducer节点,其他节点无负载。这就是极端的数据倾斜了。
解决方式:mapjoin

情形2:大表与大表join,但是分桶的判断字段0值或空值过多
后果:这些空值/0值都由一个Reducer处理,非常慢
解决方式:把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果。

6.1.4 不同数据类型关联产生数据倾斜

情形:比如用户表中user_id字段为int,log表中user_id字段既有string类型也有int类型。当按照user_id进行两个表的Join操作时。
后果:处理此特殊值的reduce耗时;只有一个reduce任务
默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分配到一个Reducer中。
解决方式:把数字类型转换成字符串类型

select * from users a
  left outer join logs b
  on a.usr_id = cast(b.user_id as string)

6.2 调优

6.2.1 hive.map.aggr=true
# 开启map端combiner
set hive.map.aggr=true;

思想
开启map combiner。在map中会做部分聚集操作,效率更高但需要更多的内存。
点评
假如map各条数据基本上不一样, 聚合没什么意义,做combiner反而画蛇添足,hive里也考虑的比较周到通过参数:
hive.groupby.mapaggr.checkinterval = 100000 (默认)
hive.map.aggr.hash.min.reduction=0.5(默认)

6.2.2 hive.groupby.skewindata=true
# 开启数据倾斜时负载均衡
set hive.groupby.skewindata=true;

思想:就是先随机分发并处理,再按照key group by来分发处理。

操作:当选项设定为true,生成的查询计划会有两个MRJob。

第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;

第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的原始GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。

点评:它使计算变成了两个mapreduce,先在第一个中在 shuffle 过程 partition 时随机给 key 打标记,使每个key 随机均匀分布到各个 reduce 上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上。

所以需要第二次的mapreduce,这次就回归正常 shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜。因为大量计算已经在第一次mr中随机分布到各个节点完成。

6.2.3 Join
6.2.3.1 关于驱动表的选取

选用join key分布最均匀的表作为驱动表。

6.2.3.2 做好列裁剪和filter操作

以达到两表做join的时候,数据量相对变小的效果。

6.2.3.3 left semi join
6.2.3.4 大小表Join - MapJoin

思想
小表关联一个超大表时,容易发生数据倾斜,使用 MapJoin把小表全部加载到内存在map端进行join。如果需要的数据在 Map 的过程中可以访问到则不再需要Reduce。

实例分析
原始sql:

select c.channel_name,count(t.requesturl) PV
 from ods.cms_channel c
 join
 (select host,requesturl from  dms.tracklog_5min where day='20151111' ) t
 on c.channel_name=t.host
 group by c.channel_name
 order by c.channel_name;

以上为小表join大表的操作,可以使用mapjoin把小表c放到内存中处理,语法很简单只需要增加 /*+ MAPJOIN(小标) */,把需要分发的表放入到内存中。

select /*+ MAPJOIN(c) */
c.channel_name,count(t.requesturl) PV
 from ods.cms_channel c
 join
 (select host,requesturl from  dms.tracklog_5min where day='20151111' ) t
 on c.channel_name=t.host
 group by c.channel_name
 order by c.channel_name;

6.2.3.5 大表Join大表 - skewjoin

当key值都是有效值时可使用hive配置:

set hive.optimize.skewjoin=true;
指定是否开启数据倾斜的join运行时优化,默认不开启即false。

set hive.skewjoin.key=100000;
判断数据倾斜的阈值,如果在join中发现同样的key超过该值,则认为是该key是倾斜key。

默认100000。一般可以设置成处理的总记录数/reduce个数的2-4倍。

set hive.optimize.skewjoin.compiletime=true;
指定是否开启数据倾斜的join编译时优化,默认不开启即false。

具体来说,会基于存储在原数据中的倾斜key,来在编译时为导致倾斜的key单独创建执行计划,而其他key也有一个执行计划用来join。然后,对上面生成的两个join执行后求并集。因此,除非相同的倾斜key同时存在于这两个join表中,否则对于引起倾斜的key的join就会优化为map-side join。

此外,该参数与hive.optimize.skewjoin之间的主要区别在于,此参数使用存储在metastore中的倾斜信息在编译时来优化执行计划。如果元数据中没有倾斜信息,则此参数无效。一般可将这两个参数都设为true。如果元数据中有倾斜信息,则hive.optimize.skewjoin不做任何操作。

6.2.3.6 小结

以上方式,都是根据数据倾斜形成的原因进行的一些变化。要么将 reduce 端的隐患在 map 端就解决,要么就是对 key 的操作,以减缓reduce 的压力。了解了原因再去寻找解决之道就相对思路多了些,方法肯定不止这几种。

6.2.4 先group再count

能先进行 group 操作的时候先进行group操作,把 key 先进行一次 reduce,之后再进行 count 或者 distinct count 操作。

6.2.5 控制空值分布

将为空的key转变为字符串加随机数或纯随机数,将因空值而造成倾斜的数据分不到多个Reducer。

注:对于异常值如果不需要的话,最好是提前在where条件里过滤掉,这样可以使计算量大大减少

实践中,可以使用case when对空值赋上随机值。此方法比直接写is not null更好,因为前者job数为1,后者为2.

使用case when实例1:

select userid, name
fromuser_info a
join (
select case
when userid is null  then  cast (rand(47)* 100000 as int )
else userid
end
from user_read_log
) b
on a.userid = b.userid

使用case when实例2:

select
    '${date}' as thedate,
    a.search_type,
    a.query,
    a.category,
    a.cat_name,
    a.brand_id,
    a.brand_name,
    a.dir_type,
    a.rewcatid,
    a.new_cat_name,
    a.new_brand_id,
    f.brand_name as new_brand_name,
    a.pv,
    a.uv,
    a.ipv,
    a.ipvuv,
    a.trans_amt,
    a.trans_num,
    a.alipay_uv
from fdi_search_query_cat_qp_temp a
left outer join brand f
on
     f.pt='${date}000000'
    and case when a.new_brand_id is null then concat('hive',rand() ) else a.new_brand_id end = f.brand_id

如果上述的方法还不能解决,比如当有多个JOIN的时候,建议建立临时表,然后拆分HIVE SQL语句。

6.2.6 压缩

设置map端输出、中间结果压缩。(不完全是解决数据倾斜的问题,但是减少了IO读写和网络传输,能提高很多效率)

6.2.7 增加Reuducer个数

默认是由参数hive.exec.reducers.bytes.per.reducer来推断需要的Reducer个数。

可通过mapred.reduce.tasks控制,默认-

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358