双活场景下MongoDB分片集群必须单中心部署config server和mongos路由决策,跨机房部署会导致路由错误、双主分裂和元数据更新阻塞;分片Replica Set需通过priority、votes、tags等显式控制选举与流量,应用层承担容灾路由责任。

双活场景下 MongoDB 分片集群不能直接跨机房部署 Sharding Router(mongos)
mongos 本身无状态,但依赖配置服务器(config server)的元数据一致性。双活数据中心间若存在网络分区或高延迟,mongos 会因无法及时同步分片路由表而返回过期或错误的 chunk 分布信息,导致写入被路由到错误分片、查询丢失数据或触发大量 moveChunk 冲突。
真实生产中,跨机房部署 mongos 实例常伴随以下现象:
- 客户端偶发
FailedToSatisfyReadPreference或NotMasterNoSlaveOk - sh.status() 显示
stale config version报警频繁 - chunk 迁移卡在
committed状态,日志持续输出waiting for majority commit
根本原因不是 mongos 本身不支持跨机房,而是它对 config server 的强实时性依赖与双活网络的弱一致性天然冲突。因此,必须将路由决策收敛到单中心,或通过应用层隔离流量。
跨机房 Replica Set 部署必须显式控制优先级与投票权
一个分片(shard)本质是独立的 Replica Set。双活容灾的关键不在“能否跨机房部署”,而在“故障时能否自动、确定地降级到单中心并保持主节点唯一”。默认配置下,MongoDB 不保证跨机房选举结果符合容灾预期。
实操中必须手动设置:
- 为每个机房的节点分配不同
priority(如机房 A:2,机房 B:1),避免平票 - 禁用非核心机房节点的
votes: 0(例如只允许机房 A 的 3 个节点参与投票,B 机房仅作读副本) - 设置
members[n].tags并配合读偏好readPreference=primaryPreferred&readPreferenceTags=region:A控制流量归属 - 确认
settings.chainingAllowed: false,防止 B 机房节点从 A 机房非主节点同步,放大延迟影响
否则可能出现:机房 A 断网后,B 机房两个节点互相认为对方已宕机,各自发起选举,产生双主(split-brain)——这是 MongoDB 最危险的状态,会导致数据覆盖写入。
配置服务器(config server)必须单中心部署,不可跨机房复制
3 节点副本集形式的 config server 是强制要求,但它绝不能横跨双活机房。因为 config server 的写操作需满足 majority commit,一旦跨机房,网络抖动就会阻塞所有分片元数据更新(如添加新分片、平衡 chunk),整个集群的 sharding 功能将停滞。
正确做法是:
- 将全部 3 个 config server 节点部署在同一机房(推荐机房 A)
- 在机房 B 部署只读
mongos实例,其连接的 config server 地址仍指向机房 A;该mongos仅用于本地应用读请求,且必须配置localThresholdMS防止因延迟误判节点离线 - 若机房 A 整体故障,需人工介入:先停掉所有
mongos,再通过rs.reconfig()将 config server 副本集强制重配到机房 B 的节点上(此时已非自动容灾,而是半自动恢复)
没有“全自动双活 config server”方案。官方文档明确指出 config server 副本集必须具备低延迟、高可靠网络,这与跨机房物理约束矛盾。
应用层必须承担路由和容灾决策责任
MongoDB 本身不提供跨机房服务发现或故障转移能力。双活成败最终取决于应用如何使用 mongos 和 Replica Set 连接字符串。
关键控制点:
- 禁止应用直连分片副本集地址,所有流量必须经
mongos(哪怕只读也走) - 应用配置两套
mongos列表(A 机房 + B 机房),由外部服务发现组件(如 Consul、Nacos)根据健康检查结果动态切换,默认指向 A 机房mongos,B 机房作为降级兜底 - 写操作必须限定在主中心(如机房 A),B 机房只允许带
readPreference=secondary的只读查询,并接受秒级延迟 - 监控项不能只看
mongos进程存活,要抓取shardingState和configServer连通性指标,延迟超 50ms 即告警
最容易被忽略的是:应用日志里出现 NotWritablePrimary 错误时,90% 情况不是数据库挂了,而是应用仍在向已失联的机房 B 的 mongos 发送写请求——这说明服务发现未生效或应用缓存了旧连接池。










