config服务器必须部署为三节点副本集(csrs),自mongodb 3.4起强制要求,存储分片元数据(如chunks、shards、balancer状态等),保障高可用与一致性,禁止手动写入config库。

config服务器不是单点,而是副本集(CSRS)
很多人误以为 config 服务器是单节点,其实从 MongoDB 3.4 开始,config 服务器必须部署为三成员副本集(CSRS),否则集群无法启动。它不承担数据存储,只存元数据——比如每个 chunk 的范围、归属分片、版本号,以及均衡器状态、分片键定义等。
关键点在于:CSRS 保证了元数据的高可用和一致性,但不解决写放大问题。所有元数据变更(如块拆分、迁移、添加分片)都必须经由 CSRS 主节点写入,并同步到 secondary。如果 CSRS 响应慢,mongos 会卡住元数据操作(例如 sh.splitAt() 超时)。
- 不要把 CSRS 和业务分片混部——它对磁盘 I/O 和网络延迟极其敏感,建议独占小规格 SSD 实例
- CSRS 的
oplog大小需显式调大(默认仅 1GB),否则在批量预分裂或紧急扩容时容易被冲掉,导致 secondary 落后甚至全量重同步 - 监控
config.configs和config.changelog集合写入延迟,超过 500ms 就该排查 CSRS 节点负载
chunk 元数据本身做了压缩和懒加载
MongoDB 不在每次写入时广播所有 chunk 信息,而是采用“按需加载 + 版本控制”机制:mongos 缓存本地一份 chunk 路由表(shard key → shard ID 映射),仅在查询命中缺失范围、或收到 invalidate 消息时才向 CSRS 拉取最新视图。
这意味着:即使集群有 10 万个 chunk,mongos 启动时也不会一次性拉全量元数据,而是随着实际查询逐步填充缓存。但这也带来风险——如果某 mongos 长期未使用,首次查询可能因元数据刷新而明显变慢。
-
mongos默认每 30 秒检查一次元数据版本,可通过setParameter调整refreshLogicalSessionCacheIntervalMillis(不影响 chunk,但相关会话元数据也走同路径) - 避免在
mongos上设置过短的maxIdleTimeMS,频繁重建连接会导致反复触发元数据刷新 - chunk 范围用 BSON MinKey/MaxKey 表达,实际存储紧凑;但如果你用复合分片键且字段值很长(如嵌套对象),会略微增加元数据体积
均衡器迁移不是实时广播,而是异步队列驱动
均衡器(balancer)本身不直接修改每个 mongos 的路由表,它只在 config 中标记迁移任务(写入 config.migrations),然后由目标分片和源分片在后台异步执行数据拷贝。真正触发 mongos 刷新元数据的,是迁移完成后的 commitChunkMigration 命令——这个命令由分片主动上报给 CSRS,再由 CSRS 广播变更。
所以元数据同步压力集中在迁移完成瞬间,而非整个迁移过程。这也是为什么设置 activeWindow 很重要:避开高峰期提交大量 commit,能有效削平元数据写入毛刺。
- 迁移失败时,
config.migrations里残留未清理的记录会持续触发mongos重试检查,需人工干预sh.stopBalancer()后清理 - 并行迁移数
migrationChunkSize不影响元数据大小,但影响 commit 密度——设为 5 意味着最多 5 个 chunk 同时完成并触发元数据更新 - 不要禁用均衡器后长期运行,否则
chunk分布严重倾斜,某次手动moveChunk可能引发连锁元数据刷新风暴
真正压垮元数据同步的,往往是人为误操作
最常被忽略的元数据压力源,不是数据量,而是高频低价值变更。比如在测试环境反复 sh.shardCollection 同一个集合、或用脚本每分钟调用 sh.splitAt() 模拟负载——这些操作都会在 config 中留下版本递增记录,迫使所有 mongos 频繁重载路由表。
CSRS 的瓶颈从来不在容量,而在写入序列化能力。一个 3 节点 CSRS,理论极限约 200–300 次/秒元数据写(取决于磁盘延迟),但实际生产中超过 50 次/秒就该警惕。
- 禁止在应用代码里动态调用分片管理命令;所有
sh.操作必须走审批流程+灰度窗口 - 用
db.getSiblingDB("config").chunks.countDocuments()定期核对 chunk 总数,突增说明有异常拆分行为 - 开启
auditLog记录所有对config库的写操作,定位谁在高频刷元数据
mongos 的懒加载策略。一旦开始怀疑元数据问题,先看 CSRS 日志里的 writeConcern 超时,再查 mongos 的 getShardVersion 耗时,而不是直接调大 chunkSize 或加 mongos 节点。











