config server必须单中心部署,因其元数据写入依赖majority commit,跨机房网络抖动会导致chunk迁移卡住、config version停滞;shard副本集可跨机房但需显式配置priority/votes/tags防split-brain;mongos须与config server同机房,否则路由表过期引发写入错误和查询失败。

config server 必须单中心部署,mongos 必须和它在同一个机房,shard 副本集可以跨机房但必须显式配置 priority、votes、tags —— 这不是可选项,而是避免元数据停滞、双主分裂、路由错乱的硬约束。
为什么 config server 绝对不能跨机房?
config server 是分片集群的元数据中枢,所有 sh.splitAt()、sh.moveChunk()、添加新分片等操作都依赖其 w: "majority" 写入成功。跨机房部署 3 节点后,一旦网络抖动或短暂分区,majority commit 就会卡住。
典型错误现象:
-
Waiting for majority commit持续出现在 config server 日志中 -
sh.status()显示 config version 长期不更新 -
db.printShardingStatus()报告 stale config version
不要试图用 w: 1 或 writeConcern: {w: "majority", wtimeout: 1000} 来“绕过”——这只会让元数据写入失败,触发更严重的路由不一致。正确做法是:3 个 config server 全部部署在同一机房(推荐主业务机房 A),哪怕该机房整体故障,也比跨机房导致元数据停滞更可控。
shard 副本集跨机房时如何防 split-brain?
每个 shard 是独立副本集,双机房默认选举逻辑无法保证主节点唯一。必须手动干预投票权和优先级:
- 机房 A 的节点设
priority: 2,机房 B 的节点设priority: 1,杜绝平票 - 机房 B 所有节点设
votes: 0,只保留读能力,不参与选举 - 为每个节点打标签,例如
{"dc": "shanghai"}和{"dc": "beijing"},并在应用连接串中显式指定readPreference=primaryPreferred&readPreferenceTags=dc:shanghai - 关闭链式复制:
settings.chainingAllowed: false,防止机房 B 节点从机房 A 的 secondary 同步,放大延迟影响
否则可能出现:机房 A 断网后,B 机房两个节点互相认为对方宕机,各自发起选举,产生双主 —— 数据覆盖写入风险极高。
mongos 为什么不能跨机房部署?
mongos 本身无状态,但它每秒轮询 config server 获取最新路由表(config.shards、config.chunks)。跨机房部署后,网络延迟会导致缓存过期、路由错乱。
典型表现:
- 客户端偶发
FailedToSatisfyReadPreference或NotMasterNoSlaveOk -
sh.status()中频繁报警 stale config version - chunk 迁移卡在
committed状态
根本原因不是 mongos 不支持跨机房,而是它对 config server 的强实时性依赖与双活网络的弱一致性天然冲突。因此,mongos 必须收敛到 config server 所在机房,不能分散部署。
应用层必须承担容灾路由责任
mongos 不复制数据,也不做跨 IDC 写负载均衡。所有写请求永远发往当前 shard 的 Primary 所在 IDC —— 如果 Primary 在 IDC-A,IDC-B 的节点只是异步同步 oplog。
若需某类业务写入就近 IDC,只能靠应用层实现:
- 按
region字段分片,确保对应分片的 Primary 固定落在目标 IDC(靠priority+votes控制) - 连接字符串中必须带
readPreferenceTags,否则tags配置完全无效 - 修改副本集配置(如
priority或tags)后,必须调用rs.reconfig();只改配置文件不重启、不执行 reconfig,变更就是白改
最常被忽略的一点:rs.reconfig() 必须传入完整配置对象,不能只传局部字段 —— 正确做法是先运行 rs.conf() 拿到当前完整配置,修改后再传入 rs.reconfig()。











