首页/数据/数仓建模速查/数据倾斜识别与加盐处理
湖仓与引擎63 条

数据倾斜识别与加盐处理

倾斜表现为个别 reducer 长尾:先按 key 统计分布定位热点,可用加盐打散(热点 key 拼随机前缀)后两阶段聚合解决。

数仓建模速查数据更新于 2026-10-13

数据倾斜是什么

数据倾斜指某个 key 的数据量远大于其他 key,导致处理该 key 的单个 reduce 任务长时间运行:其他任务早早结束,整个作业却卡在最后那一两个 task 上。定位办法是按 key 统计分布找出热点,常用解法是加盐打散——给热点 key 拼上随机前缀,先做一次局部聚合,再去掉前缀按原始 key 汇总。加盐的本质是把一个超长任务拆成多个短任务。

基本信息

典型现象少数 reduce 任务长尾,作业卡在最后几个 task
定位手段按 key 统计分布,倒序取 TOP N
常用解法加盐打散 + 两阶段聚合
兜底方案热点 key 单独处理,其余走正常流程
高发场景GROUP BY 集中维度、大表 JOIN、去重统计

典型使用场景

  • GROUP BY 高度集中的维度(如店铺、渠道)时出现长尾任务
  • 大表 JOIN:关联键分布不均,或关联键存在大量空值
  • 去重统计:单个 key 数据量过大,去重开销集中在一个任务上
  • 分区写入倾斜:少数分区数据量异常,写文件耗时远超其他分区
  • 作业耗时波动大:数据分布随业务变化,同一脚本时快时慢

定位方法

手段做法能看到什么
key 分布统计按 key 分组计数并倒序取 TOP哪些 key 是热点,差多少量级
Spark UI看 stage 内各 task 的耗时与输入大小是否存在长尾 task 及其所在分区
作业日志对比各 reduce 的输入行数与耗时倾斜发生在哪一步、哪个 key 上

定位热点

定位热点
SELECT store_id, count(1) AS cnt
FROM dwd_trade_order_di
WHERE dt='2026-10-13'
GROUP BY store_id
ORDER BY cnt DESC
LIMIT 20;   -- 取 TOP20,看最高值与中位数差几个量级

加盐两阶段聚合

加盐两阶段聚合
-- 第一阶段:给 key 拼上 0-9 的随机后缀,先把数据打散
INSERT OVERWRITE TABLE tmp_store_salted PARTITION (dt='2026-10-13')
SELECT concat(store_id,'_',cast(rand()*10 as int)) AS salt_key,
       count(1) AS cnt, sum(pay_amt) AS pay_amt
FROM dwd_trade_order_di WHERE dt='2026-10-13'
GROUP BY concat(store_id,'_',cast(rand()*10 as int));
-- 第二阶段:去掉后缀,按原始 key 再汇总一次
SELECT split(salt_key,'_')[0] AS store_id, sum(cnt) AS cnt, sum(pay_amt) AS pay_amt
FROM tmp_store_salted WHERE dt='2026-10-13'
GROUP BY split(salt_key,'_')[0];
加盐后必须在第二阶段按原始 key 再汇总一次,否则同一个门店会被拆成十份计数,结果看起来正常但数值翻倍。加盐份数也不是越多越好:份数过多会让第二阶段的聚合重新变成长尾。
只提高并行度解决不了倾斜:同一个 key 的数据始终落在同一个 reduce 分区里,任务数变多只会让那一个任务更孤立地拖住整个作业。

易错点

  • 盲目提高并行度:倾斜 key 仍然落在同一个 reduce,长尾依旧存在
  • 加盐后不做二次汇总:同一 key 被拆成多份,计数翻倍且不易察觉
  • JOIN 键存在大量空值导致倾斜:应先过滤无效值,或给空值打散标签
  • 对全部 key 无差别加盐:牺牲整体性能,而只有热点 key 才需要处理
  • 倾斜只在个别分区出现就不处理:每次作业都要等那一个 task,积少成多拖慢整个调度窗口

数据来源与参考

  • Apache Hive 官方文档:Skewed Join Optimization
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌