hive 数据倾斜

hive outline

链接

hive 空值引发的数据倾斜

大量的null值经hash取余后结果是一样的,会被标记到到同一分区,进而会被分配到一个reduce中,产生数据倾斜

解决方案:

第一种:null值没有用,可以直接对null值进行过滤

SELECT *
FROM log a
         JOIN users b
              ON a.user_id IS NOT NULL
                  AND a.user_id = b.user_id
UNION ALL
SELECT *
FROM log a
WHERE a.user_id IS NULL;

第二种:null值有用(生产中,有些空值是具备业务含义的,比如:剩余还款字段,用户某个时间点已还清贷款,数据为空,但去掉空值数据是肯定不对的,所以需要具体情况具体分析),又分为2种情况

(1)当存在很多Null值的时候,可以选择把空值数据单独筛选出来,剩余非空数据正常Join,最后再把空值数据union all上去即可

(2)特使情况下可以给Null赋上随机值,这样它们的hash结果就不一样,最终就会进到不同的reduce中

SELECT *
FROM log a
         LEFT JOIN users b ON CASE
                                  WHEN a.user_id IS NULL THEN concat('hive_', rand())
                                  ELSE a.user_id
                                  END = b.user_id;

如果A、B两表join操作,假如A表中需要join的字段为null,但是B表中需要join的字段不为null,这两个字段根本就join不上啊,为什么还会放到一个reduce中呢?

hive 数据类型不同引发的数据倾斜

比如用户表中 user_id 字段为 int,日志 表(logs)中 user_id 字段既有 string 类型也有 int 类型。当按照 user_id 进行两个表的 Join 操作时,默认的 Hash 操作会按 int 型的 id 来进行分区,这样会导致所有 string 类型 id 记录都会被分配到同一个分区中,进入到同一个 Reducer 中

解决方案:

如果key字段既有string类型也有int类型,默认的hash就都会按int类型来分配,那我们直接把int类型都转为string就好了,这样key字段都为string,hash时就按照string类型分配了:

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

hive 数据文件太大且不可切割引发的数据倾斜

当集群的数据量增长到一定规模,有些数据需要归档或者转储,这时候往往会对数据进行压缩;当对文件使用GZIP压缩等不支持文件分割操作的压缩方式,在日后有作业涉及读取压缩后的文件时,该压缩文件只会被一个任务所读取。如果该压缩文件很大,则该Map任务可能会成为作业运行的瓶颈。这种情况也就是Map读取文件的数据倾斜

解决方案:

这种数据倾斜问题没有什么好的解决方案,只能将使用GZIP压缩等不支持文件分割的文件转为bzip2和zip等支持文件分割的压缩方式

hive 数据膨胀引发的数据倾斜

在多维聚合计算时,如果进行分组聚合的字段过多,如下:

select a,b,c,count(1from log
group by a,b,c
with rollup;

注:with rollup是用来在分组统计数据的基础上再进行统计汇总,即用来得到group by的汇总信息

如果上面的log表的数据量很大,并且Map端的聚合不能很好地起到数据压缩的情况下,会导致Map端产出的数据急速膨胀,这种情况容易导致作业内存溢出的异常。如果log表含有数据倾斜key,会加剧Shuffle过程的数据倾斜

解决方案:

可以拆分上面的sql,将with rollup拆分成如下几个sql:

SELECT a, b, c, COUNT(1)
FROM log
GROUP BY a, b, c;

SELECT a, b, NULL, COUNT(1)
FROM log
GROUP BY a, b;

SELECT a, NULL, NULL, COUNT(1)
FROM log
GROUP BY a;

SELECT NULL, NULL, NULL, COUNT(1)
FROM log;

但是,上面这种方式不太好,因为现在是对3个字段进行分组聚合,那如果是5个或者10个字段呢,那么需要拆解的SQL语句会更多。

在Hive中可以通过参数 hive.new.job.grouping.set.cardinality 配置的方式自动控制作业的拆解,该参数默认值是30。表示针对grouping sets/rollups/cubes这类多维聚合的操作,如果最后拆解的键组合大于该值,会启用新的任务去处理大于该值之外的组合。如果在处理数据时,某个分组聚合的列有较大的倾斜,可以适当调小该值

hive 中最常见的数据倾斜

  • group by 数据倾斜

在一些操作中,当使用 collect_list 函数时,中间结果会放到内存中,所以如果collect_list聚合太多数据,会导致内存溢出:

-- collect_list:将分组中的某列转为一个数组返回
select s_age, collect_list(s_score) list_score
from student
group by s_age

解决方案:
一般情况下使用group by 的负载均衡机制就可以解决该问题,但这里不推荐选用group by 的负责均衡机制,先了解一下该机制的原理:该机制会在group by时启动两个mr job。第一个mr会将map端数据随机分区后送往到各个reducer,每个 reducer做部分聚合。第二个mr再将前面预处理过的数据,按照key再次聚合并输出结果

group by 的负责均衡机制的核心作用在于生成的第一个mr能够有效减少数量。但是对于collect_list这类要求全量操作所有数据中间结果的函数来说,明显起不到作用,反而因为引入新的作业增加了磁盘和网络I/O的负担,而导致性能变得更为低下,一般来说这类问题最直接的方式就是调整reduceTask的内存大小

collect_list这类函数外推荐使用group by 的负责均衡机制

-- 开启group by 的负责均衡机制
hive.groupby.skewindata=true;
  • 不影响业务的条件下,也可以使用这种方案:开启Map端聚合
-- 开启Map端聚合:Combiner
hive.map.aggr=true;
-- 在Map端进行聚合操作的条目数目
hive.groupby.mapaggr.checkinterval = 100000

适用条件:不影响业务的条件下(例如:求和可以使用,求平均值就不能使用)

原理:使用combiner 后相当于在map端提前进行 reduce,即把一个 Mapper 中的相同 key 先进行了聚合,减少 shuffle 过程中传输的数据量,以及后续Reduce 端的计算量

Combiner触发时机:

  1. 溢写文件之前会触发一次Combiner
  2. 对多个溢写文件进行merge时,也会触发一次Combiner
  • 也可以使用这种方案:实现自定义分区

原理:根据数据分布情况,自定义散列函数,将 key 均匀分配到不同 Reducer

hive 自定义分区器

  • 表join时引发的数据倾斜

大表join大表

未经优化的大表与大表JOIN

在这里插入图片描述

优化后的大表与大表JOIN

在这里插入图片描述

测试

(1)2个大表

在这里插入图片描述
(2)左表随机,右表扩容(解决大key倾斜)

select *
from (
         select id,
                concat(id, '-', ceil(rand() * 2)) as id_random,
                name
         from t1_skew
     ) a
         join
     (
         select id,
                concat(id, '-', 1) as id_random,
                name
         from t2_skew
         union all
         select id,
                concat(id, '-', 2) as id_random,
                name
         from t2_skew
     ) b
     on a.id_random = b.id_random;

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Hive数据倾斜是指在Hive中进行数据处理时,数据在不同reduce任务上分布不均匀的现象。这种情况可能导致某些reduce任务负载过重,而其他任务负载较轻。常见的数据倾斜问题包括单个key的数据量过大、空key的存在等情况。 解决Hive数据倾斜问题的方法之一是使用group by去重然后统计行数的方式,但需要注意数据倾斜问题。这种方法可以通过将数据按照某个字段进行分组,去除重复值,然后统计每个组的行数来解决数据倾斜的问题。 另一种常见的数据倾斜问题是空key的存在。当两个表进行联接操作时,联接字段可能存在很多null值,或者集中出现在某个特定的值上。这样就会导致它们计算出的哈希值相同,将它们都放到同一个reduce任务中,从而导致该任务的负载过大,而其他任务负载较轻,这也就是我们所说的数据倾斜问题。 综上所述,Hive数据倾斜是指在Hive中进行数据处理时,数据在不同reduce任务上分布不均匀的现象。解决数据倾斜的方法包括使用group by去重统计行数和处理空key的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Hive数据倾斜常见场景及解决方案(超全!!!)](https://blog.csdn.net/weixin_51981189/article/details/127419638)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值