Hive数据倾斜问题

1、数据倾斜的表现

        数据倾斜是由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点的现象。
        主要表现:任务进度长时间维持在 99%或者 100%的附近,查看任务监控页面Yarn(8088),发现只有少量 reduce 子任务未完成,因为其处理的数据量和其他的 reduce 差异过大。 单一 reduce 处理的记录数和平均记录数相差太大,通常达到好几倍之多,最长时间远大于平均时长。
        大数据领域:不患多而患不均  

2、出现的原因

        其实数据倾斜这个问题,在MapReduce编程模型中十分常见,根本原因就是大量相同的key被分配到一个reduce里,造成一个reduce任务处理不过来,但是其他的reduce任务没有数据可以处理。下面罗列一下常见的数据倾斜有哪些原因 :

1)数据类型不一致造成数据倾斜

情形: 比如用户表users中user_id字段为string,log表中user_id字段int类型。当按照user_id进行两个表的Join操作时。
解决方式:把数字类型转换成字符串类型

2)数据中出现大量的null值

分为两种情况,第一种情况,null值是异常值,就不应该出现,比如 userId 出现 null

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

 第二种情况,出现null的数据不是异常数据,需要保留。

虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。

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中),最后完成最终的聚合操作。

第二种方案:增加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;

3、多表join出现数据倾斜

解决方案一:使用参数解决

在编写 Join 查询语句时,如果确定是由于 join 出现的数据倾斜,那么请做如下设置:

#join的键对应的记录条数超过这个值则会进行分拆,值根据具体数据量设置

set hive.skewjoin.key=100000;

如果是join过程出现倾斜应该设置为true

set hive.optimize.skewjoin=false;

如果开启了,在Join过程中Hive会将计数超过阈值hive.skewjoin.key(默认100000)的倾斜key对应的行临时写进文件中,然后再启动另一个mr做map join生成结果。

通过 hive.skewjoin.mapjoin.map.tasks参数还可以控制第二个mr job的mapper数量,默认10000。

set hive.skewjoin.mapjoin.map.tasks=10000;

第二种解决方案:大小表join

MapJoin原理: 小表缓存并发送到各个节点,没有Shuffle的过程 
如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join(Reduce join),即:在Reduce阶段完成Join。
总结:
1) mapjoin --只有map没有reduce,当然也不会有shuffle
2)  common join : 就是普通的join,走MR程序

实战:

实战设置:
(1)设置自动选择Mapjoin
set hive.auto.convert.join = true; 默认为true
(2)大表小表的阈值设置(默认25M以下认为是小表):
set hive.mapjoin.smalltable.filesize = 25000000;

1) 内连接,小表放到左边或者右边都可以,hive底层会自动优化
2)左连接,小表放到后边,也就是 from 大表 left join 小表 on 大表.字段名 = 小表.字段名,底层会将小表数据加载到内存,
          走mapjoin,效率更高
3) 右连接,小表放到左边,也就是 from 小表 right join 大表 on 大表.字段名 = 小表.字段名,底层会将小表数据加载到内存,
          走mapjoin,效率更高
4)全连接, 无法触发mapjoin,无法小表放到前边或者后边

MapJoin不触发的可能得原因:内存不足
修改Hadoop中的配置文件: /opt/installs/hadoop3.1.4/etc/hadoop/mapred-site.xml
一个 Map Task 可使用的内存上限(单位:MB),默认为 1024。
<property>
  <name>mapreduce.map.memory.mb</name>
  <value>4096</value>
</property>

还可以使用大表打散、小表扩容的手段解决。

具体如下:首先看如下数据:

从上面的图可以得知,数据出现了倾斜。

使用大表打散小表扩容:

方案:

 第三种解决方案:大表大表join

         大表关联大表,使用分而治之思想+map join,对关联两表做成以join条件为分桶字段的表,并且按照同样的排序方式组织分桶数据,两表的分桶个数必须成整数倍数关系。在表数据关联的时候,将小表的数据加载到内存中,开启大表桶个数的map任务,并且将小表桶数据加载到与大表对应桶位置对应(相同或者成倍数关系)的map任务的内存中去,然后以map join的方式执行,这种方式与map join的区别一是数据进行过滤,并不是全数加载到内存中,二是数据是有序的,降低扫描次数,提升效率。由此看来SMB join 使用分而治之思想转换为多个小的map join 操作,规避shuffle 操作。

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值