oplog仅在副本集模式下存在,单节点mongod即使指定--oplogsize也不会生成真实oplog;恢复前必须确认rs.status()有输出,且目标ts未被轮转覆盖,三者缺一不可。

Oplog 存在但 mongod 没开 --replSet?恢复直接失败
Oplog 不是默认开启的——它只在副本集(replica set)模式下存在。单节点 mongod 即使加了 --oplogSize 也**不会生成真实 oplog**,local.oplog.rs 集合为空或根本不存在。这是最常被忽略的前提。
实操建议:
- 先确认是否为副本集:
rs.status()在 mongo shell 中执行,有输出才继续 - 单机开发环境误删?别指望 oplog,立刻停写、从最近备份 + journal 恢复
- 生产库必须提前部署为副本集(哪怕只用一个节点),
mongod --replSet rs0 --dbpath /data/db启动后运行rs.initiate()
从 oplog 找到「删除操作」的 ts 和 ns 字段
误删表(db.collection.drop())在 oplog 中是一条 command 类型记录,不是 delete;而 db.collection.remove({}) 是 delete 类型。两者恢复方式不同。
实操建议:
- 用
db.getSiblingDB("local").oplog.rs.find({op: "c", "o.drop": "collection_name"}).sort({$natural: -1}).limit(1)定位 drop 操作 - 关键字段:
ts(时间戳,BSON Timestamp 类型)是恢复截止点;ns(命名空间,如"mydb.mycollection")必须严格匹配 - 注意:oplog 中的
ts不是 ISODate,不能直接传给new Date();要用Timestamp(123456789, 1)构造
用 mongorestore --oplogReplay 回放到指定 ts 前一刻
--oplogReplay 不是“重放某一条”,而是从备份快照起,重放 oplog 直到遇到第一个大于等于目标 ts 的操作——所以目标 ts 必须略小于实际删除操作的 ts,否则会跳过恢复点。
实操建议:
- 先用
mongodump --out /backup/ --oplog获取带 oplog 的快照(注意:该命令要求 mongod 为副本集且权限足够) - 还原时用:
mongorestore --oplogReplay --oplogLimit "123456789:1" /backup/,其中123456789:1是Timestamp的秒+序号字符串 - 如果
oplogLimit格式错(比如少了冒号、用了毫秒),mongorestore静默忽略,直接重放全部 oplog → 数据仍丢失
恢复后查不到数据?检查 oplog.rs 是否被轮转覆盖
Oplog 是固定大小的循环日志,默认 5% 磁盘空间或 1GB(取小值)。误删后若延迟发现,对应 ts 可能已被新操作覆盖,local.oplog.rs 里根本查不到那条记录。
实操建议:
- 立即运行
db.getSiblingDB("local").oplog.rs.findOne({ts: {$lt: Timestamp(…)}})验证目标ts是否还在 - 长期运行的库建议调大 oplog:
rs.reconfig({... , oplogSizeMB: 10240})(需主节点执行,且空间充足) - 没有 oplog 备份习惯的团队,必须配合定期
mongodump --archive+ 时间戳归档,把 oplog 快照也存下来
真正卡住人的地方从来不是命令怎么写,而是 oplog 有没有、删操作在不在、时间戳能不能对上——三者缺一不可。别等删完再查 oplog 存不存在。











