61.4 数据倾斜与调优

一句话

倾斜不是 “数据多”,而是 “某个 key/分区特别多”:总数据量没变,但 99 个 task 几分钟跑完、1 个 task 跑两小时——定位靠 “各 task 输入字节的 max/avg 比”,治理靠 “加盐、预聚合、拆热 key”。

先定位,再治理

信号 看什么 判据
task 输入字节 Spark UI 的 Input Size / Shuffle Read Size max/avg > 2 即有明显倾斜
task 耗时 同一 stage 内 task 时长分布 少数 task 是其他的 5–10 倍
热点 key 采样统计 top-N key 的计数 单个 key 占分区数据 > 30%
数据分布 分区键的基数与频次 低基数或 Zipf 分布

实测:加盐把倾斜压下去

20 万条记录、Zipf α=1.3 的 key、10 个 reduce:

方案 最大分区 平均 倾斜比
未加盐 65,289 20,000 3.3×
加盐 10(key#0..9) 30,678 20,000 1.5×
加盐 100 22,768 20,000 1.1×

加盐的本质是 “把一个热 key 拆成 N 个”,让它们分散到不同 task;代价是读的时候要再合并(多一次聚合),所以只对 “可合并的聚合/计数” 好用,对 “按 key 的强顺序” 不适用。

-- 两阶段聚合:先打散局部聚合,再按原 key 汇总
SELECT k, sum(cnt) FROM (
  SELECT concat(k, '#', cast(rand()*10 as int)) AS k, count(*) AS cnt
  FROM t GROUP BY concat(k, '#', cast(rand()*10 as int))
) GROUP BY k;

六种治理手段

手段 适用 代价
加盐拆分 聚合/计数类热点 key 多一次合并
map 端预聚合 可结合律的聚合 无(应优先)
广播小表 join 小表 内存
拆分热 key 大 key(如大 V 粉丝列表) 业务改造
两阶段聚合 SQL 层倾斜 多一次 shuffle
单独处理热点 极端热点(如秒杀) 特判逻辑

反模式

反模式 后果
不看 max/avg 就 “加资源” 倾斜 task 仍是一个,加机器无效
用 rand() 打散后不再合并 结果错(每个子 key 各算各的)
对 “有序需求” 加盐 顺序被打乱,业务出错
只在 SQL 层调参 数据分布问题不会因参数变好
忽略 “空 key / null 倾斜” 大量 null 落到同一分区
不监控倾斜比 每次跑得慢都归因于 “数据量大”

三条铁律

🔑 先量化倾斜比(max/avg),再动手。

🔑 加盐必须配 “二次合并”,否则结果错。

🔑 能预聚合就别 shuffle 全量;加盐是最后手段。

自检

Q1 为什么 “加资源” 治不了数据倾斜?

▸ 答案:因为倾斜是单个 task 数据量过大:加机器只是增加 “可并行的槽位”,而那个热 key 仍然只能由一个 task 处理(同一个 key 必须落到同一分区)。除非改变分区方式(加盐/拆分),否则热点 task 的时长不变。

Q2 加盐之后为什么必须 “二次合并”?

▸ 答案:因为加盐把 key 拆成了 key#0..N,每个子 key 各自聚合出部分结果;最终答案需要按原 key 再汇总一次。少了这一步,结果会变成 “N 份部分和”,业务上就是错的——这也是加盐最容易踩的坑。

Q3 为什么 null 值也会造成倾斜?

▸ 答案:因为 null 在哈希分区里全部落到同一个分区:如果表里有大量 null(如未登录用户、未关联订单),它们会集中到一个 task,形成 “空值热点”。常见处理是 “给 null 打随机后缀” 或 “过滤后再单独处理”。

Q4 什么情况下不能用加盐?

▸ 答案:需要按 key 保序或 key 本身有业务含义的场景:如按用户顺序回放事件、按 key 做去重。加盐会破坏顺序与唯一性语义,只能用 “拆热 key + 单独处理” 或 “两阶段聚合 + 最终排序”。

Q5 倾斜比多少算 “必须处理”?

▸ 答案:经验上 max/avg > 2 就值得看,> 5 必须处理:因为 stage 的完成时间由最慢 task 决定,3× 倾斜就意味着 “这段至少多花 2 倍时间”。但也要看绝对值:数据量很小时,倾斜的绝对浪费可以忽略。

Q6 广播小表为什么能缓解 “join 倾斜”?

▸ 答案:因为它把 join 变成 map 端本地关联:大表的每个分区各自与小表 join,不再按 key 重分布大表,热 key 也就不会集中到一个 reduce task。前提是小表能放进内存,且 join 键在小表侧没有极端热点。

Q7 如何验证 “倾斜治理有效”?

▸ 答案:看三个前后对比:倾斜比(max/avg 应下降)、stage 时长(最慢 task 应接近平均)、总 shuffle 字节(加盐可能略微增加)。只降了 “平均时长” 而 max 没降,说明治理没打中热点。

关联