hive中关于常见数据倾斜的处理

2019-07-10  本文已影响0人  cefa6a30d1c3

什么是数据倾斜?

数据倾斜主要表现在,map /reduce程序执行时,reduce节点大部分执行完毕
但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多)
这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完

数据倾斜的常见操作

image.png

状态

任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。

单一reduce的记录数与平均记录数差异过大,通常可能达到3倍甚至更多。 最长时长远大于平均时长。


具体的业务场景 (出现场景)


空key转换

不随机分配

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

INSERT OVERWRITE TABLE jointable
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN 'hive' ELSE a.id END = b.id;

后果就是所有为null值的id全部都变成了相同的字符串,及其容易造成数据的倾斜(所有的key相同,相同key的数据会到同一个reduce当中去)

解决方法

为了解决这种情况,我们可以通过hive的rand函数,随记的给每一个为空的id赋上一个随机值,这样就不会造成数据倾斜 

INSERT OVERWRITE TABLE jointable
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN concat('hive', rand()) ELSE a.id END = b.id;

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

用户表中user_id字段为int,log表中user_id字段既有string类型也有int类型。
  当按照user_id进行两个表的Join操作时,默认的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)

group by造成数据倾斜

使用Hive对数据做一些类型统计的时候遇到过某种类型的数据量特别多,而其他类型数据的数据量特别少。
  当按照类型进行group by的时候,会将相同的group by字段的reduce任务需要的数据拉取到同一个节点进行聚合,
    而当其中每一组的数据量过大时,会出现其他组的计算已经完成而这里还没计算完成,
      其他节点的一直等待这个节点的任务执行完成,所以会看到一直map 100%  reduce 99%的情况。
解决方式:
## hive.map.aggr=true  (默认true) 这个配置项代表是否在map端进行聚合,相当于Combiner
## hive.groupby.skewindata=true(默认false)
有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。
第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的
第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作

通用的一些数据倾斜的处理方法

1.reduce个数太少
reduce数太少set mapred.reduce.tasks=800;  作用域也是Session级
1)调整reduce个数方法一
(1)每个Reduce处理的数据量默认是256MB
      hive.exec.reducers.bytes.per.reducer=256123456
(2)每个任务最大的reduce数,默认为1009
      hive.exec.reducers.max=1009
(3)计算reducer数的公式
      N=min(参数2,总输入数据量/参数1)

2)调整reduce个数方法二
  在hadoop的mapred-default.xml文件中修改
  设置每个job的Reduce个数
      set mapreduce.job.reduces = 15;

3)reduce个数并不是越多越好(需要注意)
  1)过多的启动和初始化reduce也会消耗时间和资源;
  2)另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;

需要注意的是: 默认是先设置hive.exec.reducers.bytes.per.reducer这个参数,设置了后hive会自动计算reduce的个数,因此两个参数一般不同时使用

2.当HiveQL中包含count(distinct)时
   如果数据量非常大,执行如select a,count(distinct b) from t group by a;类型的SQL时,会出现数据倾斜的问题。

   解决方法:使用sum...group by代替。如select a,sum(1) from (select a, b from t group by a,b) group by a;

借鉴:
https://blog.csdn.net/qq_26442553/article/details/80866723
https://www.cnblogs.com/ggjucheng/archive/2013/01/03/2842860.html

上一篇 下一篇

猜你喜欢

热点阅读