10.大数据学习之旅——hive2

Hive解决数据倾斜问题


概述

什么是数据倾斜以及数据倾斜是怎么产生的?
简单来说数据倾斜就是数据的key 的分化严重不均,造成一部分数据很多,一部分数据很少的局面。
举个 word count 的入门例子,它的map 阶段就是形成 (“aaa”,1)的形式,然后在reduce 阶段进
行 value 相加,得出 “aaa” 出现的次数。若进行 word count 的文本有100G,其中 80G 全部是 “aaa” 剩
下 20G 是其余单词,那就会形成 80G 的数据量交给一个 reduce 进行相加,其余 20G 根据 key 不同分散到不
同 reduce 进行相加的情况。如此就造成了数据倾斜,临床反应就是 reduce 跑到 99%然后一直在原地等着 那
80G 的reduce 跑完。

如此一来 80G 的 aaa 将发往同一个 reducer ,由此就可以知道 reduce 最后 1% 的工作在等什么了。

为什么说数据倾斜与业务逻辑和数据量有关?

从另外角度看数据倾斜,其本质还是在单台节点在执行那一部分数据reduce任务的时候,由于数据量大,跑不
动,造成任务卡住。若是这台节点机器内存够大,CPU、网络等资源充足,跑 80G 左右的数据量和跑10M 数
据量所耗时间不是很大差距,那么也就不存在问题,倾斜就倾斜吧,反正机器跑的动。所以机器配置和数据量
存在一个合理的比例,一旦数据量远超机器的极限,那么不管每个key的数据如何分布,总会有一个key的数据
量超出机器的能力,造成 reduce 缓慢甚至卡顿。

业务逻辑造成的数据倾斜会多很多,日常使用过程中,容易造成数据倾斜的原因可以归纳为几点:
1)group by
2)distinct count(distinct xx)
3)join

如何处理group by的数据倾斜问题

1、调优参数
set hive.groupby.skewindata=true;
hive.groupby.skewindata=true:数据倾斜时负载均衡,当选项设定为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已经有了很大的改善,因此基本解决数据倾斜。

Hive优化

1)map side join
mapJoin的主要意思就是,当链接的两个表是一个比较小的表和一个特别大的表的时
候,我们把比较小的table直接放到内存中去,然后再对比较大的表格进行map操
作。join就发生在map操作的时候,每当扫描一个大的table中的数据,就要去去查看
小表的数据,哪条与之相符,继而进行连接。这里的join并不会涉及reduce操
作。map端join的优势就是在于没有shuffle,在实际的应用中,我们这样设置:
set hive.auto.convert.join=true;
此外,hive有一个参数:hive.mapjoin.smalltable.filesize,默认值是25mb(其中一
个表大小小于25mb时,自动启用mapjoin)
要求:在hive做join时,要求小表在前(左)
2)join语句优化
优化前
select m.cid,u.id form order m join customer u on m.cid=u.id where
m.dt=’20160801’;
优化后
select m.cid,u.id from (select cid from order where dt=’20160801’)m
join customer u on m.cid = u.id
注意:Hive在做join时,小表写在前(左边)。
3)group by 优化
hive.groupby.skewindata=true
如果group by过程出现倾斜,应该设置为true
4)count distinct 优化
优化前

select count(distinct id )from tablename

注意:count操作是全局计数,在底层转换成MRjob时,用于计数的分区(reduceTask)
只能有一个。

优化后

select count(*) from (select distinct id from tablename)tmp;

此外,再设定一下reduce的任务数量。
注意:count这种全局计数的操作,Hive只会用一个Reduce来实现

日常统计场景中,我们经常会对一段时期内的字段进行消重并统计数量,SQL语句类似

SELECT COUNT( DISTINCT id ) FROM TABLE_NAME WHERE …;
这条语句是从一个表的符合WHERE条件的记录中统计不重复的id的总数。
该语句转化为MapReduce作业后执行示意图如下,图中还列出了我们实验作业中
Reduce阶段的数据规模:
在这里插入图片描述

由于引入了DISTINCT,因此在Map阶段无法利用combine对输出结果消重,必须将id
作为Key输出,在Reduce阶段再对来自于不同Map Task、相同Key的结果进行消重,
计入最终统计值。
我们看到作业运行时的Reduce Task个数为1,对于统计大数据量时,这会导致最终
Map的全部输出由单个的ReduceTask处理。这唯一的Reduce Task需要Shuffle大量的
数据,并且进行排序聚合等处理,这使得它成为整个作业的IO和运算瓶颈。
经过上述分析后,我们尝试显式地增大Reduce Task个数来提高Reduce阶段的并发,
使每一个Reduce Task的数据处理量控制在2G左右。具体设置如下:
set mapred.reduce.tasks=100
调整后我们发现这一参数并没有影响实际Reduce Task个数,Hive运行时输出
“Number of reduce tasks determined at compile time: 1”。
原因是Hive在处理COUNT这种“全聚合(full aggregates)”计算时,它会忽略用户指
定的Reduce Task数,而强制使用1。

所以我们只能采用变通的方法来绕过这一限制。我们利用Hive对嵌套语句的支持,将原
来一个MapReduce作业转换为两个作业,在第一阶段选出全部的非重复id,在第二阶
段再对这些已消重的id进行计数。这样在第一阶段我们可以通过增大Reduce的并发
数,并发处理Map输出。在第二阶段,由于id已经消重,因此COUNT(*)操作在Map阶
段不需要输出原id数据,只输出一个合并后的计数即可。这样即使第二阶段Hive强制指
定一个Reduce Task,极少量的Map输出数据也不会使单一的Reduce Task成为瓶颈。
改进后的SQL语句如下:

SELECT COUNT(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值