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