数据倾斜

某些分区键对应的数据量与流量远大于其他分区:表现为个别实例 CPU 或存储显著偏高、任务出现长尾;需要重新选择分布键或对热点加盐拆分。

数据倾斜的表现与代价

数据倾斜指某些分区键对应的数据量或流量远大于其他分区:表现为个别分片或实例的 CPU、磁盘与延迟明显偏高,批处理任务出现长尾(大部分任务早早完成,少数任务拖到最后)。代价是整体资源按最热分片配置,成本上升而利用率不高,同时热点分片的过载会直接变成超时与失败。治理手段有三类:换更均匀的分布键、对确认的热点键加盐拆分、以及为热点单独建立处理路径。

基本信息

识别对比各分片行数、吞吐与延迟分布,找明显偏差
加盐热点键追加随机后缀分散写入,读取时聚合
重选改用分布更均匀且仍贴合查询的分片键
局限加盐会增加读取与统计的复杂度,只对确认的热点键使用

典型使用场景

  • 分库分表路由:按用户或商户分片时出现少数超大租户
  • 批处理与聚合计算:单个键的数据量超出单任务处理能力,任务长尾
  • 消息分区:某个业务键的消息量远超其他键,单个消费者被打满
  • 缓存分片:热点键集中到少数节点,节点负载不均
  • 指标统计:按维度聚合时高基数维度造成倾斜

加盐拆分示意

加盐拆分示意
原键:user_id=42 → shard = 42 % 16 → 单分片热点
加盐:key = '42#' + rand(0..3) → 写入分散到 4 个分片

读取:并发读 4 个盐值分片后合并
统计:按原始 user_id 聚合,忽略后缀
注意:只对确认的热点键加盐,避免全量加盐

倾斜类型与对策

类型特征对策
键分布不均少数键数据量远大于其他键更换分片键或引入二级散列
单键热点某个键的访问量远超其他键加盐拆分写入,读取时并发合并
空值或默认值键大量记录落到同一个分片为缺失值分配独立分片或改写默认键
阶段性倾斜大促或批量任务期间集中到少数分片临时扩大并发或提前拆分热点任务

治理步骤

  • 识别:按分片统计行数、QPS 与延迟分布,找明显离群分片
  • 分类:键分布不均、单键热点与空值键,治理手段各不相同
  • 改造:先对确认的热点键加盐或改写路由,避免全量重构
  • 验证:治理后用同一统计口径复测,确认分片间差异收敛
  • 监控:把分片间差异做成常态指标,避免改造后再次失衡
倾斜治理要同时验证查询模式:加盐拆分后按原键查询需要合并多份数据,如果读取路径无法并发合并,查询延迟反而会上升。
用哈希取模分片时扩容会改变键到分片的映射:需要一致性哈希或预分配分片方案,否则一次扩容就触发全量数据迁移,倾斜治理的成果也会被打乱。

易错点

  • 按取值不均的字段分片,长尾分片持续过载,整体资源按最热分片配置
  • 加盐后读取未合并,返回不完整数据,问题在上线后由业务侧发现
  • 只按平均值观察集群负载,个别分片过热被平均值掩盖
  • 哈希取模分片在扩容时映射全变,引发全量迁移与长时间不一致
  • 空值或默认值大量落到同一分片,形成隐性热点且长期无人识别

数据来源与参考

  • 《数据密集型应用系统设计》(Kleppmann)第 6 章
  • Apache Spark 文档:数据倾斜处理
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌