图解 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...

相关推荐
葫芦和十三1 小时前
图解 MongoDB 27|分片策略:范围分片 vs 哈希分片
后端·mongodb·agent
paopaokaka_luck2 小时前
英语单词学习系统的设计与实现(基于艾宾浩斯遗忘曲线的智能复习机制、语音朗读、多题型测试与错题自动收录、Echarts图形化分析)
vue.js·spring boot·后端·echarts
我叫黑大帅2 小时前
MySQL 并发插入竞态问题:原子写入实践指南
后端·mysql·面试
zhangxingchao3 小时前
AI大模型核心八:从 Agent Skill、长文档 RAG 到知识库更新与训练策略
前端·人工智能·后端
我叫黑大帅3 小时前
别再手动写 updated_at了,这坑我踩过
后端·面试·go
zhangxingchao4 小时前
AI大模型核心七:从 Workflow、RAG、记忆治理到幂等性
前端·人工智能·后端
犀利豆5 小时前
AI in Harness(二)
java·人工智能·后端
IT_陈寒5 小时前
Python装饰器竟然偷偷改了函数名?这个坑我爬了三天
前端·人工智能·后端
bkl_92136 小时前
GPT-Image-2 文生图:如何稳定生成完整的人物全身照?
后端·gpt·restful