一、原因
主要是数据分布不均:某些键(Key)的数据量远大于其他键,导致处理这些键的任务负载过重。map是根据key分配到不同的reduce。
同时,虽然 有些是业务逻辑导致:热门商品的购买记录远多于其他商品;但是数据倾斜会传播:在生产作业上,倾斜问题可能被放大或传播到后续阶段。
二、解决方法
(1)数据预处理:数据清洗,制定数据有效性清洗规则,避免无效数据大量集中于某个key,或让分区更合理;
(2)优化查询:
1、JOIN的时候的倾斜:对倾斜列的数据,进行单独处理。也就是遇到倾斜列的数据的时候,直接找一个中间目录临时存储,当前MR不去处理,等当前MR完成后,在单独处理这个倾斜的数据集。
2、GROUPBY的时候的倾斜:利用MapReduce的Combina 机制,在Map端完成预聚合操作。因为,分组是必聚合的,所以,我们可以做预聚合。参数:hive.map.aggr=true
3、join的时候剔除发生倾斜的无效数据,比如大量的0;
(3)专门的处理技术:
-
Salting的解决方案:为键添加一个随机的前缀或后缀(称为“盐值”),将原本集中的数据分散到多个分区中。例如,将键
user_id
转换为user_id_salt
,其中salt
是一个随机值(如1到N之间的整数)
-- 示例:为user_id添加盐值
SELECT
user_id,
CONCAT(user_id, '_', FLOOR(RAND() * 4)) AS user_id_salt -- 假设盐值为0到3
FROM
user_table;
2、二次聚合:
-
将聚合操作分为两个阶段:
-
局部聚合:先对数据进行分组和初步聚合,减少数据量。
-
全局聚合:再对局部聚合的结果进行最终聚合。
-
(4)特别注意,已经存在倾斜的字段,如果作为join的关联键,容易产生大量笛卡尔积,一层一层传导,造成数据爆炸,影响生产任务。