Config Server 的 oplog 不记录元数据变更,误删分片元数据后无法通过 oplog.rs 恢复;唯一可行路径是使用早于误删时间的完整 config 库备份,在单节点模式下用 mongorestore --drop 恢复。

Config Server 的 oplog 不是普通数据库的 oplog
误删分片元数据(比如 config.databases、config.collections、config.chunks)后,第一反应查 oplog.rs 恢复?停手。Config Server 的 oplog 是 local.oplog.rs,但它**不记录元数据变更**——MongoDB 分片集群里,所有对 config 库的写入都绕过 oplog,直接落盘。你查 db.oplog.rs.find() 会发现空空如也,或只有心跳、replSetUpdatePosition 这类内部操作。
真正记录元数据变更的是 config.system.sessions 和 config.transactions?也不是。它们只管会话和事务状态,不管分片拓扑。所以:「从 Config Server 的 oplog 恢复」这条路,从源头就走不通。
唯一可行路径:从最近一次 config 库备份恢复
分片元数据不可逆、不可重建,必须依赖备份。但这里有几个硬条件:
- 你得有
mongodump --uri "mongodb://config-server:27019" --db config的完整备份(不是只 dump 某个集合) - 备份时间必须早于误删操作发生的时间点
- 恢复时 Config Server 必须处于单节点模式(
replSet: null或停掉副本集),否则写入会被拒绝 -
mongorestore必须加--drop,否则新旧元数据冲突会导致 balancer 拒绝启动、shard 节点无法加入集群
示例命令(假设备份在 /backup/config-2024-04-15):
mongorestore --uri "mongodb://localhost:27019" --db config --drop /backup/config-2024-04-15/config/
注意:mongorestore 默认不覆盖 _id 字段,但 config 库里很多集合(如 config.shards)依赖 _id 唯一性,--drop 是必须项,跳过它等于埋雷。
没有备份?别碰 config 库的任何写操作
一旦确认无可用备份,立刻停止所有 sh. 命令(sh.addShard、sh.removeShard)、禁用 balancer(sh.setBalancerState(false)),并断开所有应用连接。此时 config 库虽残缺,但部分分片可能仍在服务——强行修复反而会让 chunk 元数据与实际数据错位,导致查询返回空或重复结果。
可尝试的极限操作(仅限紧急诊断):
- 用
db.config.chunks.findOne({})看是否还有残留 chunk 记录 - 检查每个 shard 的
adminCommand({listShards: 1})输出,比对config.shards是否缺失条目 - 若只剩
config.shards丢失,且你知道所有 shard 的 host 地址,可手动重建(但config.databases和config.collections缺失则无法安全推断库/集合分片策略)
手动补 config 库风险极高:一个 uuid 字段填错,整个集合就无法被 mongos 识别;primary 字段指向不存在的 database,会导致后续 use db 报 DatabaseNotFound 错误。
为什么线上环境几乎没人做 config 库定时备份
不是不想,是不敢。MongoDB 官方明确警告:mongodump 备份 config 库时,必须保证集群完全静默(balancer 关闭、无 chunk 迁移、无集合创建/删除)。而生产环境极少满足这个条件——哪怕 30 秒的窗口,也可能漏掉关键变更。更现实的做法是:
- 把
config.shards、config.databases、config.collections三个集合导出为 JSON,每日 cron 执行(mongo config --eval "printjson(db.shards.find().toArray())" > shards.json) - 用
mongodump --db config --collection chunks --query '{"lastmod": {"$gt": ISODate("...")}}'增量抓取 chunk 变更(需配合日志分析时间点) - 在部署自动化脚本里,每次执行
sh.shardCollection后,自动记录该集合的分片键、zone、chunk 分布快照到外部存储
真正的危险不在恢复操作本身,而在于你以为 oplog 可靠,结果花两小时回滚,却发现根本没写进去——那种时刻,连 db.currentOp() 都救不了你。










