前面讲片键决定了数据怎么分布,但没讲数据分布后怎么保持均衡。新数据持续写入、加新 shard、不同片键范围数据量不均——这些都会让各 shard 的数据量失衡。负责保持均衡的是 balancer(均衡器),它操作的基本单位是 chunk(块)

理解 chunk 和 balancer,才能解释几个分片运维问题:为什么数据会倾斜到某个 shard?为什么 balancer 一直在迁移却均衡不了?为什么会出现 jumbo chunk?这些都落在这套机制上。

先把机制边界说清楚

**Chunk(块)**是 MongoDB 把分片数据划分的逻辑单位。一个 chunk 是一段连续的片键范围,包含这范围内所有文档。比如片键是数值,[1, 1000) 是一个 chunk。chunk 不是物理文件,而是逻辑划分——config server 记录每个 chunk 的片键范围和所属 shard。

chunk 有大小上限(默认 64MB,较新版本可配 128MB)。当一个 chunk 的数据超过上限,它会**分裂(split)**成两个小 chunk。分裂是自动的,不需要迁移数据,只是更新 config server 的元数据(把一个范围拆成两个)。

**Balancer(均衡器)**是后台进程,定期检查各 shard 的 chunk 数量。如果数量差超过阈值(通常 2 个以上),balancer 会从 chunk 多的 shard 迁移 chunk 到 chunk 少的 shard,直到均衡。

chunk 的分裂

chunk 分裂的意义是让数据分布能随数据增长细化。一开始一个集合可能只有少数几个 chunk,随着数据增加,chunk 不断分裂,数据分布越来越细,balancer 才能把它们更均匀地分散到各 shard。

分裂的触发是 chunk 大小达到上限。分裂时,MongoDB 在片键范围内找一个中间点,把原 chunk 拆成两个。这个中间点的选择基于数据分布(不是简单取中值),尽量让两个新 chunk 大小均衡。

分裂本身很轻——只是更新 config server 元数据,不搬移数据。真正搬数据的是 balancer 的迁移。

balancer 的迁移

块与迁移:balancer 怎么均衡数据

当 balancer 发现 shard 间 chunk 数量失衡,它会启动迁移。迁移一个 chunk 的过程:

  1. balancer 选一个源 shard(chunk 多的)和目标 shard(chunk 少的)。
  2. 源 shard 把 chunk 的数据拷贝到目标 shard(期间仍接受读写,源仍是权威)。
  3. 拷贝完成,更新 config server 元数据,把 chunk 的所属 shard 改为目标。
  4. 源 shard 删除已迁移的 chunk 数据。

迁移期间有额外开销:源 shard 要拷数据(IO 和网络),目标 shard 要写入数据。大 chunk 的迁移开销更明显。如果迁移频繁或 chunk 很大,可能影响正常查询性能。

所以 balancer 可以配置迁移窗口(比如只在夜间低峰迁移),或在做维护时临时关闭 balancer。监控 balancer 的迁移频率和耗时,能判断集群是否健康——频繁迁移说明数据持续倾斜,可能是片键问题。

jumbo chunk:无法迁移的痛点

chunk 迁移有个前提:chunk 大小不能超过迁移上限(通常是 chunk 大小上限的某个比例)。如果某个 chunk 太大,超出了迁移能力,它会被标记为 jumbo chunk——balancer 无法迁移它。

jumbo chunk 的根因几乎都是片键基数太低。比如片键是 status(只有几个值),所有 active 文档挤在一个片键范围,这个 chunk 不断长大却无法分裂(因为片键值就那么几个,没有中间点可拆),最终变成 jumbo。balancer 动不了它,数据永久倾斜在这个 shard。

jumbo chunk 的后果:数据倾斜、单 shard 过载、集群无法均衡。临时手段是手动清除 jumbo 标记(让 balancer 尝试迁移),但根本解法是改片键——选一个基数足够高的片键,让 chunk 能正常分裂和迁移。这又回到第 26 篇的结论:片键设计是分片的命运决定点。

加 shard 时怎么均衡

加新 shard 是分片集群扩容的方式。新 shard 加入后,它没有 chunk,balancer 会从其他 shard 迁移 chunk 过来,直到均衡。这个「再均衡」过程会持续一段时间(取决于数据量),期间有迁移开销。

所以加 shard 要错峰,且预期它会触发一波 chunk 迁移。加 shard 后各 shard 的 chunk 数量应该趋于均衡,数据分布更均匀,单 shard 负载下降。

判断框架

  • chunk 是片键范围的逻辑块,满了会自动分裂。
  • balancer 在 shard 间迁移 chunk 保持均衡,迁移有 IO/网络开销。
  • 频繁迁移 = 数据持续倾斜,要查片键是不是选错了。
  • jumbo chunk 无法迁移,根因是片键基数低,治本要改片键。
  • 加 shard 触发再均衡,错峰操作。
  • balancer 可配置迁移窗口或临时关闭,做维护时用。

下一篇讲分片键的各种陷阱,把片键相关的坑收束。


关于十三Tech

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

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

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

十三Tech公众号二维码