核心要点
Shuffle 把数据按 key 跨节点重分布,伴随磁盘写、网络传输与序列化,是主要性能瓶颈
数据倾斜:某些 key 数据量远大于其他,导致个别 Task 拖慢整个 Stage
聚合类倾斜用加盐打散 + 两阶段聚合(局部聚合再全局聚合)
Join 倾斜用广播 join(小表广播)或拆出热点 key 单独处理;开启 AQE 自动调分区/拆斜
标准回答
Shuffle 的代价
宽依赖算子(groupByKey、reduceByKey、join、repartition)需要把相同 key 的数据汇聚到同一分区,这一过程称 Shuffle:上游写中间文件、下游拉取,涉及磁盘 IO、网络传输与序列化,是大数据作业最常见的性能瓶颈。优化原则是减少 Shuffle 量、避免倾斜。
识别数据倾斜
倾斜表现为 Stage 中大多数 Task 很快完成、个别 Task 长时间运行甚至 OOM。通过 Spark UI 看各 Task 的输入/Shuffle Read 大小即可定位热点 key(如 null、默认值、超大客户)。
优化手段
1)聚合倾斜:给 key 加随机前缀(加盐)打散到多分区做局部聚合,再去盐做全局聚合,即两阶段聚合。
2)Join 倾斜:小表用广播 join(Broadcast)避免 Shuffle;大表热点 key 拆分单独 join 再 union。
3)调整并行度/分区数,避免单分区过大;优先 reduceByKey 而非 groupByKey(map 端预聚合)。
4)开启 AQE(自适应查询执行),运行时合并小分区、动态切换 join、自动拆分倾斜分区。
常见误区
⚠️ 常见踩坑
盲目增大分区数不能解决倾斜,因为同一个热点 key 仍会落到单个分区,必须先打散 key。也别忘了过滤掉无意义的脏 key(如 null)往往是性价比最高的优化。
追问
追问 1:reduceByKey 和 groupByKey 哪个更好,为什么?
优先 reduceByKey。它在 map 端先做本地预聚合(combine)再 Shuffle,显著减少跨网络的数据量;groupByKey 把所有同 key 值全部 Shuffle 到下游再聚合,数据量大且易 OOM。仅当确实需要原始全部值时才用 groupByKey。
追问 2:AQE 具体做了哪些自适应优化?
AQE 在 Shuffle 后基于真实统计动态调整:合并过小的分区减少 Task 数;把超大倾斜分区拆成多个子分区并行;当一侧表实际很小时自动改用广播 join。它弥补了静态优化器无法预知运行时数据分布的不足。
延伸学习
与本题相关的知识库文章、术语、工具与行业资讯。