在线跨机房迁移mongodb分片集群本质是分阶段保障数据一致性与服务可用性,需通过dts等工具拉取全量+增量、回放各shard oplog,并严格规避元数据操作;禁用rsync/mongodump因无法保留分片拓扑、chunk边界及路由一致性。

在线跨机房迁移 MongoDB 分片集群,本质不是“一键切换”,而是分阶段控制数据一致性与服务可用性。核心在于:用外部同步工具(如 DTS、mongosync 或自研 pipeline)拉取全量 + 增量,再靠 oplog 回放补足写入延迟,同时确保元数据操作被严格规避。
为什么不能直接 rsync 或 mongodump/mongorestore?
分片集群的元数据(config 数据库)、shard 间数据分布、chunk 边界、balancer 状态全部依赖实时协调。冷备份会丢失正在迁移中的 chunk,且无法保证 _id 全局唯一性在目标端不冲突;mongodump 对分片集群默认只导出逻辑视图,不保留物理分片归属。
常见错误现象:sh.status() 在目标端显示 chunk 数为 0,或所有数据都落在一个 shard 上;应用写入后查不到,但 mongosh 直连对应 shard 却能查到——说明路由元数据没对齐。
实操建议:
- 禁止在迁移过程中执行任何
sh.shardCollection()、sh.splitAt()、sh.moveChunk() - 源集群的
config数据库必须可读(DTS 等工具需从中拉取分片拓扑),但禁止写入 - 若使用自研同步,务必解析
config.chunks和config.databases,而非仅靠listDatabases
DTS 迁移分片集群时,oplog 回放如何配置才不丢写?
DTS 的增量同步底层就是读取源 oplog,但它默认不处理分片集群特有的 oplog 分散问题:每个 shard 自己维护一份 oplog.rs,而 mongos 不存 oplog。所以 DTS 必须分别连接每个 shard 的 primary 节点来拉取 oplog,并按时间戳合并排序。
容易踩的坑:
- 未开启
oplog大小预留:源 shard 的oplog容量太小(比如默认 5% 磁盘),在长周期迁移中会被覆盖,导致增量断点丢失 - 忽略
writeConcern:DTS 写入目标时若用{w:1},可能在目标 shard 故障时静默丢数据;应设为{w:"majority"}并确认目标副本集状态正常 - 未过滤掉
config库变更:DTS 若把源config.settings的balancer开关也同步过去,会导致目标集群自动触发非法 chunk 迁移
参数差异示例:DTS 控制台中「增量同步起点」应设为「指定时间点」,该时间点必须晚于全量任务启动时刻,且早于任一 shard 的 oplog 最老条目(可用 db.oplog.rs.find().sort({$natural:-1}).limit(1) 查)。
如何验证目标分片集群的 chunk 分布和路由一致性?
迁移完成后,不能只看 sh.status() 输出是否“看起来正常”。真实风险藏在 chunk 的物理位置与 mongos 缓存的路由表是否一致。
实操建议:
- 对比源/目标的
config.chunks.countDocuments({}),数值必须完全相等;若有差,说明某些 chunk 没被同步或被跳过 - 随机抽 10 个分片键值,用
sh.findShard("db.coll", {shardKey: "xxx"})查路由,再直连对应 shard 执行db.coll.findOne({shardKey: "xxx"}),确认数据存在且内容一致 - 检查目标
mongos的shardingState:运行db.runCommand({getShardMap: 1}),确认所有 shard 的host字段指向的是目标集群内部地址,而非源集群 IP
性能影响:若目标 mongos 路由缓存未刷新,首次查询会触发 config.shards 重拉,延迟明显;建议迁移后手动执行 sh.stopBalancer() → sh.startBalancer() 强制刷新缓存。
跨机房网络抖动下,oplog 回放延迟怎么监控和止损?
机房间带宽波动、防火墙策略变更、DNS 解析失败都会导致 oplog 拉取卡住,但 DTS 默认只报“同步延迟 > 60s”这种模糊告警,不告诉你卡在哪一环。
关键监控点:
- 源端每个 shard 的
oplog最新时间戳:db.oplog.rs.find().sort({$natural:-1}).limit(1).tstamp - DTS 任务中各 shard 子任务的「当前同步位点」时间戳(控制台可查)
- 目标端
config.oplog.$main(如果用了 DTS 的 oplog 中继模式)或直接查目标 shard 的oplog.rs最新条目
止损动作:
- 延迟 > 300s 时,立即暂停增量任务,检查源 shard 网络连通性及
oplog是否被截断 - 若发现某 shard 的 oplog 已被覆盖,必须重新做该 shard 的全量 + 新增增量,不能强行续传
- 切记:不要在迁移中途重启
mongos,它会清空路由缓存,导致后续查询全部 fallback 到全广播模式,拖垮整个集群
最易被忽略的一点:目标集群的 config 副本集必须用 WiredTiger 引擎,且不能含仲裁节点——这是 MongoDB 官方对分片集群配置服务器的硬性要求,否则 sh.status() 会返回异常,但错误信息极不直观,往往要等到 balancer 启动失败才暴露。











