Spark/Flink 数据倾斜治理:热点 Key、加盐和两阶段聚合怎么选

长文技术整理分类:性能优化阅读 3420评论 262026-04-16
数据倾斜要先分清 Join、聚合、窗口还是 Sink 倾斜,不同类型处理方式不同。

这类问题为什么值得单独写

Spark/Flink 数据倾斜治理:热点 Key、加盐和两阶段聚合怎么选 不是一个单点技巧,而是一组工程取舍。生产环境里,真正困难的不是把 demo 跑通,而是当数据量、并发、权限、历史包袱和多人协作都出现时,系统还能稳定运行。

围绕 数据倾斜、加盐、热点Key,要同时考虑业务口径、存储模型、计算成本、失败恢复和可观测性。只看某一个参数,往往会把问题从一个组件转移到另一个组件。

核心概念拆解

第一层是数据模型:字段怎么定义、主键是什么、时间字段用哪个、是否允许迟到和修正。第二层是计算模型:批处理、流处理、增量处理还是查询时计算。第三层是服务模型:报表查询、接口查询、离线导出、AI 检索使用的是不是同一套口径。

层面要确认的问题
数据来源、主键、时间、去重、更新删除
计算并行度、状态、Shuffle、窗口、重跑
服务延迟、QPS、权限、缓存、降级
治理owner、血缘、质量、告警、版本

常用检查方式

-- 行数和主键去重
SELECT count(*) AS rows, count(distinct id) AS ids
FROM target_table
WHERE dt='${bizdate}';

-- 分区数据波动
SELECT dt, count(*) cnt
FROM target_table
WHERE dt >= date_sub('${bizdate}', 7)
GROUP BY dt
ORDER BY dt;

-- 核心金额对账
SELECT sum(amount), count(distinct user_id)
FROM target_table
WHERE dt='${bizdate}';

生产落地建议

常见误区

第一个误区是只追新技术,不解决数据口径和质量。第二个误区是把所有逻辑堆到一层,导致后面无法复用。第三个误区是没有补偿链路,一旦出现脏数据只能手工修。第四个误区是没有评测和对账,系统看似正常,结果已经偏了好几天。

上线检查清单

加盐不是随便 concat 一个随机数

加盐要保证最终口径能还原。以大表 Join 小表为例,大表热点 Key 加 0~N 的盐,小表对应热点 Key 复制 N 份,非热点 Key 不处理。Join 完后如果是聚合指标,还要按原始 Key 二次聚合。

-- 大表热点加盐
CASE WHEN key IN ('unknown','0') THEN concat(key, '_', cast(rand()*20 as int)) ELSE key END AS join_key

-- 小表热点复制盐值,非热点保持原样
SELECT concat(key, '_', salt) AS join_key, attrs
FROM dim_hot_key LATERAL VIEW explode(sequence(0,19)) t AS salt;

Flink 里要特别注意状态大小。热点 Key 如果进入窗口聚合,单个 subtask 的 RocksDB 状态会持续膨胀。可以先做 local pre-aggregate,再 keyBy 原 Key 做最终聚合,减少进入主窗口的数据量。

延伸阅读和落地建议

本文按公开技术资料和生产经验重新整理,没有复制原文。真正落地到你的环境时,建议补充:集群版本、资源规格、任务截图、SQL 执行计划、核心监控曲线、上线前后对比数据。这样文章会更像真实生产复盘,也更适合长期维护。