前面几篇讲了片键设计、范围/哈希分片、chunk 和 balancer。这一篇把分片上线后最常踩的三个坑收束起来:jumbo chunk、孤儿文档、写入热点。它们表现形式不同,但根源大多指向片键设计或运维操作。

理解这三个陷阱,能在分片集群出问题时快速定位:数据为什么倾斜?计数为什么重复?单 shard 为什么写满?这些都是分片运维的高频问题。

陷阱一:jumbo chunk 无法迁移

成因:片键基数太低。一个片键范围(chunk)内的文档太多,超过了 chunk 迁移上限,balancer 无法迁移它。

比如片键是 status(只有几个值),所有 active 文档挤在一个片键范围。这个 chunk 不断长大,却无法分裂(片键值太少,没有中间点可拆),最终超出迁移能力,被标记为 jumbo。

现象:balancer 一直在尝试均衡却均衡不了,数据永久倾斜在某个 shard。监控会看到某个 shard 的数据量远超其他,且 balancer 迁移日志里这个 chunk 反复失败。

解法:根本解法是改片键——选一个基数足够高的片键,让 chunk 能正常分裂和迁移。临时手段是手动清除 jumbo 标记(clearJumboFlag),让 balancer 尝试迁移,但如果片键不改,jumbo 会再次出现。

陷阱二:孤儿文档

成因:chunk 迁移中断或残留。正常迁移时,源 shard 把 chunk 拷到目标后删除源数据。但如果迁移中途失败、或异常重启,源 shard 可能残留已迁移的文档副本——这些文档在 config server 元数据里已经不属于这个 shard,但物理上还在它的磁盘上,成为「孤儿」。

现象:孤儿文档会导致数据被重复计算。比如 count() 可能比实际多(孤儿被算了两次),聚合结果异常。更隐蔽的是,某些查询可能从孤儿 shard 返回本该不返回的文档。

解法:用 cleanupOrphaned 命令清理指定集合的孤儿文档,它会扫描并删除不属于该 shard 的残留数据。定期运行 cleanupOrphaned 是分片运维的好习惯。新版本 MongoDB 在 chunk 迁移时更严格地清理源数据,孤儿问题已减少,但仍需警惕。

陷阱三:写入热点

成因:片键单调递增 + 范围分片。时间戳、自增 ID、ObjectId 这类单调递增的片键,配合范围分片,会让所有新数据都落在「最大值」那个 chunk(通常在最后一个 shard),形成写入热点。

现象:单 shard 承受全部写入压力,CPU/IO 打满,其他 shard 闲置。分片集群的负载分散能力完全失效。监控会看到某个 shard 的 opcounters 远高于其他。

解法:改用哈希分片(把单调递增的值打散),或用复合片键(加一个分散前缀)。这又回到第 27 篇的范围/哈希选择——单调递增键不适合单独范围分片。

三个陷阱的共同根源

分片键陷阱

把三个陷阱放一起看,共同点是:它们都让「分了等于没分」。jumbo 让数据倾斜、孤儿让数据重复、热点让负载集中。分片集群失去了负载分散的意义,还增加了复杂度。

更关键的是,jumbo 和热点都根植于片键设计,而片键极难更改。所以这三个陷阱的预防,比治疗重要得多:

  • 上线前压测片键分布:用真实数据量测试片键的数据分布是否均匀、会不会形成热点。
  • 监控各 shard 数据量:数据量持续失衡说明片键有问题。
  • 监控 balancer 迁移频率:频繁迁移或迁移失败,指向 jumbo 或倾斜。
  • 定期 cleanupOrphaned:防止孤儿累积。

一个真实的教训

很多分片事故的剧本是这样的:业务上线时选了个「看起来合理」的片键(比如时间戳,因为想按时间查),用了范围分片。初期数据少,一切正常。随着数据增长,写入热点出现(时间戳递增,全堆一个 shard),但因为是递增的,jumbo 还没形成。等到发现单 shard 写满,想改片键已经很难(数据量大)。最后要么忍着倾斜,要么走艰难的 reshardCollection。

这个教训的核心是:片键设计要在上线前用未来的数据规模验证,不能只看当下。第 26 篇强调的「片键极难改」,在这一篇体现为具体的运维事故。

判断框架

  • jumbo chunk:片键基数低 → 改高基数片键。
  • 孤儿文档:迁移残留 → cleanupOrphaned 定期清理。
  • 写入热点:单调递增 + 范围分片 → 哈希分片或复合片键。
  • 三个陷阱都让分片失效,预防比治疗重要。
  • 上线前压测片键分布,监控 shard 数据量和 balancer 迁移。
  • 片键是命运决定点,设计阶段多花时间。

下一篇是分片阶段的收尾,讲查询路由和广播查询。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 MongoDB」,欢迎关注公众号 「十三Tech」。后续会按分片集群和架构选型这条线更新。

十三Tech公众号二维码