题目重点:从任务耗时和分区大小定位倾斜,按聚合、join 与读写热点分别选 salting、广播或预聚合。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 教学例子是按 customer_id 分区做聚合或 join;有一个热 key 占 40% 记录,其余 key 均匀。40% 只是演示数字,非题目规模。
- 假设有可查看的任务耗时、输入行数、shuffle bytes 和 spill 指标;具体执行引擎/版本的自动优化能力未作为前提。
解题路线
- 先确诊:看同一 stage 的分区输入大小、shuffle read、运行时间与 spill,区分数据倾斜、机器慢、网络问题和少量大行。按 key 直方图找热点,并确认 null/默认值是否把大量记录集中。
- 聚合热 key 可做局部预聚合减少 shuffle;若聚合可结合,如 sum/count,先局部汇总再全局合并。Distinct/median 等不可直接相加的量需用集合/草图或精确二阶段逻辑,不能套 sum 模板。
- 大表 join 热 key 可把热 key 单独拆支路:若一侧足够小,广播该侧避免大 shuffle;否则对热 key 加盐到 S 份,同时复制对应小侧记录到 S 份,再去盐合并。复制带来 S 倍小侧数据/内存开销,选 S 依据峰值分区与资源预算。
- 若倾斜来自分区字段低基数、文件大小差异或日期峰值,调整分区/重分桶和文件布局可能比 join salting 更合适。对热点在线写还需不同的 key 设计/缓冲,与离线 shuffle 倾斜区别。
- 治理后比较 p95/p99 task time、stage wall time、shuffle/spill、输出行数与结果校验;性能提升不能以漏 key 或重复 join 行为代价。
手动走一遍
1000 万行按客户 join,客户 H 占 400 万行。均匀 hash 后 H 全落一分区,其他任务 1 分钟结束而 H 跑 20 分钟。若另一表 H 只有 100 行,可把这 100 行复制到 16 个盐分区并把大表 H 随机分 16 份,理论上每份约 25 万行,但会复制 1600 行小侧数据,还需核 join 输出不重不漏。
规模与取舍
均匀分区下每任务处理约 N/P;单一热 key 比例 f 时一个分区至少 Ω(fN)。盐成 S 份后热分区工作近 fN/S,但小侧复制约 S·M_hot,额外网络/内存随 S 增加。具体耗时受 IO、内存和执行器数量影响。
易错点与追问
容易失分的边界
- 只看到任务慢就直接加机器,不查分区分布。
- 所有 skew 都用 salting,不区分聚合与 join。
- 小侧复制没有按盐匹配,结果重复/漏行。
- 对不可结合的统计量做简单局部相加。
- 把在线热键写与离线 shuffle skew 混成一类。
继续深挖
- 热 key 是 null 时怎样处理?
- 广播 join 何时会把执行器内存打爆?
- 多表 join 中一个热 key 怎样隔离?
- 自动 skew join 优化何时仍不足?
- 治理后如何证明结果完全一致?
