图解 MongoDB 28|块与迁移:balancer 怎么均衡数据

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

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

先把机制边界说清楚

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

chunk 有大小上限(较新版本如 6.0.3+ 默认 128MB,更早版本默认 64MB)。老版本(6.0.3 之前)当一个 chunk 的数据超过上限,它会**自动分裂(split)**成两个小 chunk;6.0.3+ 不再按大小自动分裂,而是由 balancer 在迁移需要时才分裂。分裂只是更新 config server 的元数据(把一个范围拆成两个),不搬移数据。

**Balancer(均衡器)**是运行在 config server 主节点上的后台线程(自 3.4 起不再独立进程),定期检查各 shard 的数据量。如果数量差超过阈值(阈值随集合 chunk 总数变化:少于 20 个时为 2,21--80 时为 4,超过 80 时为 8),balancer 会从 chunk 多的 shard 迁移 chunk 到 chunk 少的 shard,直到均衡。

chunk 的分裂

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

老版本中,分裂的触发是 chunk 大小达到上限;6.0.3+ 后,chunk 主要在 balancer 迁移时按需分裂。分裂时,MongoDB 在片键范围内找一个中间点,把原 chunk 拆成两个。这个中间点的选择基于数据分布(不是简单取中值),尽量让两个新 chunk 大小均衡。

分裂本身很轻------只是更新 config server 元数据,不搬移数据。真正搬数据的是 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 是片键范围的逻辑块;老版本满了自动分裂,6.0.3+ 改为 balancer 迁移时按需分裂。
  • balancer 在 shard 间迁移 chunk 保持均衡,迁移有 IO/网络开销。
  • 频繁迁移 = 数据持续倾斜,要查片键是不是选错了。
  • jumbo chunk 无法迁移,根因是片键基数低,治本要改片键。
  • 加 shard 触发再均衡,错峰操作。
  • balancer 可配置迁移窗口或临时关闭,做维护时用。

架构评审会盯住什么:Chunk 与 balancer

真正要落地时,先抓住这个事实:chunk 是迁移单位,balancer 通过迁移 chunk 均衡数据。

写设计文档时,迁移不是免费操作,会消耗网络、IO,并可能影响热点分布。 分片和治理问题不能只看节点数量,要看片键、chunk、路由命中、热点和恢复演练。

追问到现场

反常识追问一:这个设计等到数据增长后会先暴露什么问题?

chunk 是迁移单位,balancer 通过迁移 chunk 均衡数据。

反常识追问二:什么情况下这个结论会失效?

迁移不是免费操作,会消耗网络、IO,并可能影响热点分布。

反常识追问三:用哪些证据确认它真的成立?

看 chunk 分布、迁移频率、jumbo chunk、balancer 窗口和业务峰值。

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


关于十三Tech

我是十三,长期关注服务端架构、数据库、中间件和 AI 工程实践。

我相信好的技术文章应该能回到真实系统里,帮人少踩一次坑。


关于十三Tech

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

相信 AI 是程序员的最佳搭档,帮助每一位开发者驾驭 AI。

公众号搜索「十三Tech」

本文首发:rubyfun.cn/posts/%E5%9...

相关推荐
猿究院_夏燊7 小时前
Spring Bean 生命周期
java·后端·spring
CCblandy9 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
我是人✓9 小时前
SpringBoot项目的五种创建方式
java·spring boot·后端
念念清晰10 小时前
000-OpenJDK17 源码构建:MacOS环境(M芯片)
java·后端
来福猿11 小时前
SpringCloud Config 源码分析:配置拉取、刷新与多环境管理
后端·spring·spring cloud
IT_陈寒13 小时前
React组件莫名重渲染?你可能忘了这个小细节
前端·人工智能·后端
用户98883218717413 小时前
给 .NET 网络调用设定“预算”:用 CancellationTokenSource.CancelAfter 处理超时取消
后端
清风儿32913 小时前
一块不会说话的电表,把我们折腾了半个月
后端
预知同行13 小时前
深入解析 MoE 混合专家模型:从 Router 到 All-to-All 的架构全景与生产实践
后端·架构
upala13 小时前
【仓颉语言入门 · 第二篇 第 8 课】
后端