MongoDB集群的备份和恢复之mongodump和mysqlrestore
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
目录
一.mongodump和mongorestore概述
1.mongodump和mongorestore概述
mongodump和mongorestore可以实现物理备份,日常备份恢复时使用,导出的是二进制文件。
mongodump能够在MongoDB运行时进行备份,它的工作原理是对运行的MongoDB做查询,然后将所有查到的文档写入磁盘,但是存在的问题是使用mongodump产生的备份不一定是数据的实时快照。
如果我们在备份时对数据库进行写入操作,则备份出来的文件可能不完全和MongoDB实时数据相等。
另外,在备份时可能会对其他客户端性能产生不利的影响。
使用mongodump备份最灵活,但速度上也是最慢的,mongodump出来的数据不能表示某个时间点,只是某个时间段。
2.备份工具对比
mongoexport/mongoimport:
- 1.导入导出的是JSON格式数据;
- 2.属于文本数据,可读性强但体积较大;
- 3.支持MongoDB跨版本;
- 4.只保留数据部分,不保留索引,账户等其他基础信息;
mongodump和mongorestore:
- 1.导入导出的是BSON格式数据;
- 2.属于二进制数据,体积小但对人类几乎没有可读性;
- 3.当跨版本时存在一定的兼容性;
在一些MongoDB版本之间,BSON格式可能会随版本不同而有所不同,所以不同版本之间用mongodump/mongorestore可能存在兼容性问题,当无法使用BSON进行跨版本的数据迁移的时候,使用JSON格式即mongoexport/mongoimport是一个可选项。
3.分片集备份和复制集备份差异概述
分片集备份和复制集备份原理相同,不过存在以下差异:
- 1.应分别为每个分片和config备份,如果有3个分片,即需要分别进行3个分片和config共4个备份;
- 2.分片集备份不仅考虑一个分片内的一致性问题,还要考虑分片间的一致性问题,因此每个片要能够恢复到同一个时间点;
- 3.如果在备份期间发生均衡的数据迁移,会造成数据丢失,所以备份前需要停止balancer;
二.mongodump/mongorestore备份工具实战
1.mongodump备份
1.1 常用参数解读
[root@node-exporter41 ~]# mongodump --help
...
-h, --host=<hostname>
指定数据库宿主机的IP。
-u, --username=<username>
指定数据库的用户名。
-p, --password=<password>
指定数据库的密码。
-d, --db=<database-name>
指定数据库的名称。
-c, --collection=<collection-name>
指定collection的名称。
-o, --out=<directory-path>
指定要导出的文件名称。
-q, --query=
指定要导出数据的过滤条件。
-j, --numParallelCollections=
并行导出的数量,默认为4。
--oplog
备份的同时备份oplog,此选项是"replica set"或者"master/slave"模式专用。
1.2 备份数据
1.备份所有数据库
[root@node-exporter41 ~]# mongodump -o /opt/mongodb-backup-all-`date "+%F-%T"`
[root@node-exporter41 ~]# ll /opt/
total 12
drwxr-xr-x 3 root root 4096 Jun 3 21:29 ./
drwxr-xr-x 22 root root 4096 Nov 12 2024 ../
drwxr-xr-x 4 root root 4096 Jun 3 21:29 mongodb-backup-all-2025-06-03-21:29:03/
[root@node-exporter41 ~]#
2.备份指定库
[root@node-exporter41 ~]# mongodump -d yinzhengjie -o /opt/mongodb-backup-custom-yinzhengjie
3.备份指定库下的集合
[root@node-exporter41 ~]# mongodump -d yinzhengjie -c blog -o /opt/mongodb-backup-custom-yinzhengjie
4.完全备份并压缩
[root@node-exporter41 ~]# mongodump --gzip -o /opt/mongodb-backup-all-gzip
2./mongorestore恢复
2.1 常用参数解读
[root@node-exporter41 ~]# mongorestore --help
...
-h, --host=<hostname>
指定数据库宿主机的IP。
-u, --username=<username>
指定数据库的用户名。
-p, --password=<password>
指定数据库的密码。
-d, --db=<database-name>
指定数据库的名称。
-c, --collection=<collection-name>
指定collection的名称。
-o, --out=<directory-path>
指定要导出的文件名称。
-q, --query=
指定要导出数据的过滤条件。
--authenticationDatabase=<database-name>
指定验证数据的名称。
--gzip
指定备份时压缩。
--oplogReplay
指定恢复完数据文件后再做重放oplog,默认重放"dump/oplog.bson"。
--oplogFile=<filename>
指定需要重放oplog文件路径。
--oplogLimit=<seconds>[:ordinal]
指定重放oplog时截止到指定时间点。
--drop
指定恢复的时候把之前的结合drop掉。
2.2 恢复数据
1.删除数据库
test> use yinzhengjie
switched to db yinzhengjie
yinzhengjie> db.dropDatabase()
{ ok: 1, dropped: 'yinzhengjie' }
yinzhengjie> show dbs
admin 40.00 KiB
config 60.00 KiB
local 72.00 KiB
yinzhengjie>
yinzhengjie> show tables
yinzhengjie>
2.还原整个数据库(需要指定数据库的目录)
[root@node-exporter41 ~]# mongorestore -d yinzhengjie /opt/mongodb-backup-custom-yinzhengjie/yinzhengjie/
三.MongoDB复制集环境基于oplog恢复数据
1.什么是oplog
MongoDB的oplog类似于MySQL的binlog,记录了MongoDB数据的更新,仅支持复制集,不支持单节点。
在replica set中oplog是一个定容集合(capped collection,固定大小),保存在local库的db.oplog.rs。
它的默认大小事磁盘空间的5%,可以通过"--oplogSizeMB"参数进行修改。默认的 oplog 大小具有以下限制:
- 最小oplog 大小为 990 MB。如果 5% 的可用磁盘空间或物理内存(以存储引擎为准)小于 990 MB,则默认的 oplog 大小为 990 MB。
- 默认最大的 oplog 大小为 50 GB。如果 5% 的可用磁盘空间或物理内存(根据您的存储引擎而定)大于 50 GB,则默认 oplog 大小为 50 GB。
oplog记录的是整个MongoDB实例一端时间内数据库的所有写(插入/更新/删除)操作,当空间用完时新纪录自动覆盖最老的记录,其覆盖范围被称为oplog时间窗口。
需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为单位时间内的更新次数不同而变化。
至少需要预留MongoDB的1个全备的周期大小。
默认情况下,MongoDB不设置oplog保留期,并自动从醉酒的条目开始截断oplog,以保持配置的最大oplog大小。
oplog有个非常重要的特性,即幂等性(idempotent),即对一个数据集合,使用oplog中记录的操作被重放时,无论被重放多少次,其结果会是一样的。比如,如果oplog中记录的是一个插入操作,并不会因为你重放了两次,数据库就会得到两条相同的记录。
参考链接:
https://www.mongodb.com/zh-cn/docs/manual/core/replica-set-oplog/
2.准备复制集环境
2.1 安装MongoDB基础环境
参考链接:
https://www.cnblogs.com/yinzhengjie/p/18792668
实战案例:
1 解压安装包
[root@node-exporter41 ~]# tar xf yinzhengjie-autoInstallMongoDB.tar.gz
[root@node-exporter42 ~]# tar xf yinzhengjie-autoInstallMongoDB.tar.gz
[root@node-exporter43 ~]# tar xf yinzhengjie-autoInstallMongoDB.tar.gz
2 安装MongoDB环境
[root@node-exporter41 ~]# ./install-mongodb.sh i
[root@node-exporter42 ~]# ./install-mongodb.sh i
[root@node-exporter43 ~]# ./install-mongodb.sh i
2.2 修改MongoDB的配置文件
1.修改MongoDB的配置文件
[root@node-exporter41 ~]# cat > /yinzhengjie/softwares/mongodb/conf/mongo.conf <<EOF
systemLog:
destination: file
path: "/yinzhengjie/softwares/mongodb/log/mongodb.log"
logAppend: true
storage:
dbPath: "/yinzhengjie/softwares/mongodb/data/"
journal:
commitIntervalMs: 100
processManagement:
fork: true
net:
port: 27017
bindIp: 0.0.0.0
replication:
replSetName: yinzhengjie-mongodb-rs
EOF
2 将配置文件同步到集群其他节点
[root@node-exporter41 ~]# scp /yinzhengjie/softwares/mongodb/conf/mongo.conf 10.0.0.42:/yinzhengjie/softwares/mongodb/conf/
[root@node-exporter41 ~]# scp /yinzhengjie/softwares/mongodb/conf/mongo.conf 10.0.0.43:/yinzhengjie/softwares/mongodb/conf/
3.重启MongoDB服务
[root@node-exporter41 ~]# systemctl restart mongod.service
[root@node-exporter42 ~]# systemctl restart mongod.service
[root@node-exporter43 ~]# systemctl restart mongod.service
2.3 任意配置复制集1主2从
[root@node-exporter41 ~]# mongosh
Current Mongosh Log ID: 67e555e5e32a8bef1201337a
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.2
Using MongoDB: 8.0.5
Using Mongosh: 2.4.2
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
------
...
test> config={_id:"yinzhengjie-mongodb-rs",members:[{_id:0,host: '10.0.0.41:27017'},{_id:1,host: '10.0.0.42:27017'},{_id:2,host: '10.0.0.43:27017'}]}
{
_id: 'yinzhengjie-mongodb-rs',
members: [
{ _id: 0, host: '10.0.0.41:27017' },
{ _id: 1, host: '10.0.0.42:27017' },
{ _id: 2, host: '10.0.0.43:27017' }
]
}
test>
test> printjson(config)
{
_id: 'yinzhengjie-mongodb-rs',
members: [
{
_id: 0,
host: '10.0.0.41:27017'
},
{
_id: 1,
host: '10.0.0.42:27017'
},
{
_id: 2,
host: '10.0.0.43:27017'
}
]
}
test>
核心代码:
config={_id:"yinzhengjie-mongodb-rs",members:[{_id:0,host: '10.0.0.41:27017'},{_id:1,host: '10.0.0.42:27017'},{_id:2,host: '10.0.0.43:27017'}]}
2.4 任意节点初始化并启动复制集
1.任意节点(比如"node-exporter41")初始化配置,观察命令行提示符
[root@node-exporter41 ~]# mongosh
Current Mongosh Log ID: 67e555e5e32a8bef1201337a
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.2
Using MongoDB: 8.0.5
Using Mongosh: 2.4.2
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
------
...
------
test>
test> rs.initiate(config) # 启动初始化配置
{
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1748960844, i: 1 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1748960844, i: 1 })
}
yinzhengjie-mongodb-rs [direct: secondary] test>
yinzhengjie-mongodb-rs [direct: secondary] test> rs.isMaster() # 判断谁是主节点
{
topologyVersion: {
processId: ObjectId('683f050e35c655b00dc45a6f'),
counter: Long('6')
},
hosts: [ '10.0.0.41:27017', '10.0.0.42:27017', '10.0.0.43:27017' ],
setName: 'yinzhengjie-mongodb-rs',
setVersion: 1,
ismaster: true, # 整个是主节点
secondary: false,
primary: '10.0.0.41:27017', # 主节点的IP地址及端口信息
me: '10.0.0.41:27017',
electionId: ObjectId('7fffffff0000000000000001'),
lastWrite: {
opTime: { ts: Timestamp({ t: 1748960854, i: 16 }), t: Long('1') },
lastWriteDate: ISODate('2025-06-03T14:27:34.000Z'),
majorityOpTime: { ts: Timestamp({ t: 1748960854, i: 16 }), t: Long('1') },
majorityWriteDate: ISODate('2025-06-03T14:27:34.000Z')
},
maxBsonObjectSize: 16777216,
maxMessageSizeBytes: 48000000,
maxWriteBatchSize: 100000,
localTime: ISODate('2025-06-03T14:27:53.264Z'),
logicalSessionTimeoutMinutes: 30,
connectionId: 2,
minWireVersion: 0,
maxWireVersion: 25,
readOnly: false,
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1748960854, i: 16 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1748960854, i: 16 }),
isWritablePrimary: true
}
yinzhengjie-mongodb-rs [direct: primary] test>
2.观察"node-exporter42"节点命令行提示符
[root@node-exporter42 ~]# mongosh
Current Mongosh Log ID: 67e5566798e5d8e08501337a
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.2
Using MongoDB: 8.0.5
Using Mongosh: 2.4.2
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
------
...
------
yinzhengjie-mongodb-rs [direct: secondary] test>
2.观察"node-exporter43"节点命令行提示符
[root@node-exporter43 ~]# mongosh
Current Mongosh Log ID: 67e5571dbb93cf26c601337a
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.2
Using MongoDB: 8.0.5
Using Mongosh: 2.4.2
For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/
------
...
------
yinzhengjie-mongodb-rs [direct: secondary] test>
2.5 查看复制集和oplog信息
yinzhengjie-mongodb-rs [direct: primary] test> rs.printReplicationInfo()
actual oplog size
'1725.055419921875 MB'
---
configured oplog size
'1725.055419921875 MB'
---
log length start to end
'283 secs (0.08 hrs)'
---
oplog first event time
'Tue Jun 03 2025 22:27:24 GMT+0800 (China Standard Time)'
---
oplog last event time
'Tue Jun 03 2025 22:32:07 GMT+0800 (China Standard Time)'
---
now
'Tue Jun 03 2025 22:32:10 GMT+0800 (China Standard Time)'
yinzhengjie-mongodb-rs [direct: primary] test>
2.6 添加测试数据验证配置高可用
1.主库写入测试数据
yinzhengjie-mongodb-rs [direct: secondary] test>
{
acknowledged: true,
insertedId: ObjectId('67e5594cbb93cf26c6015a8a')
}
yinzhengjie-mongodb-replicaset [direct: primary] test> db.teacher.countDocuments()
10000
yinzhengjie-mongodb-replicaset [direct: primary] test>
2.从库查看数据
yinzhengjie-mongodb-replicaset [direct: secondary] test> db
test
yinzhengjie-mongodb-replicaset [direct: secondary] test> db.teacher.countDocuments()
10000
yinzhengjie-mongodb-replicaset [direct: secondary] test>
3.插入大量数据并进行oplog备份
3.1 插入大量数据(目的时备份时数据一直在写入)
1.主库插入数据
yinzhengjie-mongodb-rs [direct: primary] test> use yinzhengjie
switched to db yinzhengjie
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> for(i=0;i<1000000;i++){db.teacher.insertOne({tid: i, name: "杰哥讲运维"+i,age: 18,date: new Date()})}
2.从库查看已经插入的数据条数
yinzhengjie-mongodb-rs [direct: secondary] test> use yinzhengjie
switched to db yinzhengjie
yinzhengjie-mongodb-rs [direct: secondary] yinzhengjie> db.teacher.countDocuments()
38537
yinzhengjie-mongodb-rs [direct: secondary] yinzhengjie>
3.2 备份数据
[root@node-exporter41 ~]# mkdir /opt/yinzhengjie-oplog-backup
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# mongodump --oplog -o /opt/yinzhengjie-oplog-backup
2025-06-03T22:37:47.855+0800 writing admin.system.version to /opt/yinzhengjie-oplog-backup/admin/system.version.bson
2025-06-03T22:37:47.858+0800 done dumping admin.system.version (1 document)
2025-06-03T22:37:47.858+0800 writing yinzhengjie.teacher to /opt/yinzhengjie-oplog-backup/yinzhengjie/teacher.bson
2025-06-03T22:37:47.930+0800 done dumping yinzhengjie.teacher (36941 documents)
2025-06-03T22:37:47.933+0800 writing captured oplog to
2025-06-03T22:37:47.934+0800 dumped 20 oplog entries # 表示备份时有20条记录没有备份,但oplog有记录。
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# ll /opt/yinzhengjie-oplog-backup
total 28
drwxr-xr-x 4 root root 4096 Jun 3 22:37 ./
drwxr-xr-x 6 root root 4096 Jun 3 22:37 ../
drwxr-xr-x 2 root root 4096 Jun 3 22:37 admin/
-rw-r--r-- 1 root root 7580 Jun 3 22:37 oplog.bson
-rw-r--r-- 1 root root 50 Jun 3 22:37 prelude.json
drwxr-xr-x 2 root root 4096 Jun 3 22:37 yinzhengjie/
[root@node-exporter41 ~]#
3.3 查看oplog日志
[root@node-exporter41 ~]# bsondump /opt/yinzhengjie-oplog-backup/oplog.bson | head -1
{"lsid":{"id":{"$binary":{"base64":"nyiyv5hqQZW/g6Fn/Gg7nQ==","subType":"04"}},"uid":{"$binary":{"base64":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","subType":"00"}}},"txnNumber":{"$numberLong":"36931"},"op":"i","ns":"yinzhengjie.teacher","ui":{"$binary":{"base64":"h2JfEZifRhyE+YHZf55ZzQ==","subType":"04"}},"o":{"_id":{"$oid":"683f08bb57e46b30b801c3bd"},"tid":{"$numberInt":"36930"},"name":"杰哥讲运维36930","age":{"$numberInt":"18"},"date":{"$date":{"$numberLong":"1748961467840"}}},"o2":{"_id":{"$oid":"683f08bb57e46b30b801c3bd"}},"stmtId":{"$numberInt":"0"},"ts":{"$timestamp":{"t":1748961467,"i":222}},"t":{"$numberLong":"1"},"v":{"$numberLong":"2"},"wall":{"$date":{"$numberLong":"1748961467841"}},"prevOpTime":{"ts":{"$timestamp":{"t":0,"i":0}},"t":{"$numberLong":"-1"}}}
[root@node-exporter41 ~]#
4 查看oplog
4.1 查看所有的oplog
yinzhengjie-mongodb-rs [direct: primary] test> use local
switched to db local
yinzhengjie-mongodb-rs [direct: primary] local> db.oplog.rs.find().pretty()
[
{
op: 'n',
ns: '',
o: { msg: 'initiating set' },
ts: Timestamp({ t: 1748960844, i: 1 }),
v: Long('2'),
wall: ISODate('2025-06-03T14:27:24.375Z')
},
{
op: 'c',
ns: 'config.$cmd',
ui: UUID('93480a27-3692-48a8-805d-525f9396a501'),
o: {
create: 'transactions',
idIndex: { v: 2, key: { _id: 1 }, name: '_id_' }
},
ts: Timestamp({ t: 1748960854, i: 2 }),
t: Long('1'),
v: Long('2'),
wall: ISODate('2025-06-03T14:27:34.430Z')
},
...,
{
op: 'i',
ns: 'admin.system.keys',
ui: UUID('e9716e9f-9dab-44f2-8c1c-48d02a59c6ca'),
o: {
_id: Long('7511729669914230790'),
purpose: 'HMAC',
key: Binary.createFromBase64('ItT/Wk4K2ewRzbvBceNGdWYzRnY=', 0),
expiresAt: Timestamp({ t: 1764512854, i: 0 })
},
o2: { _id: Long('7511729669914230790') },
ts: Timestamp({ t: 1748960854, i: 11 }),
t: Long('1'),
v: Long('2'),
wall: ISODate('2025-06-03T14:27:34.477Z')
},
...
]
Type "it" for more
yinzhengjie-mongodb-rs [direct: primary] local>
4.2 查看指定类型的oplog
温馨提示:
查看创建操作的oplog,其中op字段的拥有以下常见的值:
- i: 表示insert
- u: 表示update
- d: 表示delete
- c: 表示DDL语句
- n: 表示note。
实战案例:
yinzhengjie-mongodb-rs [direct: primary] local> db.oplog.rs.find({op: "c"}).pretty()
[
{
op: 'c',
ns: 'config.$cmd',
ui: UUID('93480a27-3692-48a8-805d-525f9396a501'),
o: {
create: 'transactions',
idIndex: { v: 2, key: { _id: 1 }, name: '_id_' }
},
ts: Timestamp({ t: 1748960854, i: 2 }),
t: Long('1'),
v: Long('2'),
wall: ISODate('2025-06-03T14:27:34.430Z')
},
...,
{
op: 'c',
ns: 'yinzhengjie.$cmd',
ui: UUID('87625f11-989f-461c-84f9-81d97f9e59cd'),
o: {
create: 'teacher',
idIndex: { v: 2, key: { _id: 1 }, name: '_id_' }
},
ts: Timestamp({ t: 1748961315, i: 1 }),
t: Long('1'),
v: Long('2'),
wall: ISODate('2025-06-03T14:35:15.878Z')
}
]
yinzhengjie-mongodb-rs [direct: primary] local>
5.利用oplog还原数据案例
5.1 删除表
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.teacher.countDocuments()
255640
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.teacher.drop()
true
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
5.2 不使用oplog恢复数据
1.不使用oplog恢复数据
[root@node-exporter41 ~]# mongorestore --drop /opt/yinzhengjie-oplog-backup/
2025-06-03T22:55:18.596+0800 preparing collections to restore from
2025-06-03T22:55:18.596+0800 don't know what to do with file "/opt/yinzhengjie-oplog-backup/prelude.json", skipping...
2025-06-03T22:55:18.596+0800 reading metadata for yinzhengjie.teacher from /opt/yinzhengjie-oplog-backup/yinzhengjie/teacher.metadata.json
2025-06-03T22:55:18.607+0800 restoring yinzhengjie.teacher from /opt/yinzhengjie-oplog-backup/yinzhengjie/teacher.bson
2025-06-03T22:55:19.152+0800 finished restoring yinzhengjie.teacher (36941 documents, 0 failures)
2025-06-03T22:55:19.152+0800 no indexes to restore for collection yinzhengjie.teacher
2025-06-03T22:55:19.152+0800 36941 document(s) restored successfully. 0 document(s) failed to restore.
[root@node-exporter41 ~]#
2.查看文档数量
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
teacher
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.teacher.countDocuments()
36941
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
3.再次删除数据
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.teacher.drop()
true
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
5.3 使用oplog恢复数据【恢复的数据多】
1.使用oplog恢复数据
[root@node-exporter41 ~]# mongorestore --oplogReplay --drop /opt/yinzhengjie-oplog-backup/
2025-06-03T22:56:46.819+0800 preparing collections to restore from
2025-06-03T22:56:46.819+0800 don't know what to do with file "/opt/yinzhengjie-oplog-backup/prelude.json", skipping...
2025-06-03T22:56:46.820+0800 reading metadata for yinzhengjie.teacher from /opt/yinzhengjie-oplog-backup/yinzhengjie/teacher.metadata.json
2025-06-03T22:56:46.831+0800 restoring yinzhengjie.teacher from /opt/yinzhengjie-oplog-backup/yinzhengjie/teacher.bson
2025-06-03T22:56:47.369+0800 finished restoring yinzhengjie.teacher (36941 documents, 0 failures)
2025-06-03T22:56:47.369+0800 replaying oplog
2025-06-03T22:56:47.405+0800 applied 20 oplog entries
2025-06-03T22:56:47.405+0800 no indexes to restore for collection yinzhengjie.teacher
2025-06-03T22:56:47.405+0800 36941 document(s) restored successfully. 0 document(s) failed to restore.
[root@node-exporter41 ~]#
2.查看文档数量
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
teacher
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.teacher.countDocuments()
36950
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
6.利用oplog恢复误删除表思路
6.1 故障恢复思路
故障说明:
每天凌晨2点全量备份,oplog恢复窗口为48h,上午10点yinzhengjie库的k8s业务表被误删除。
故障恢复思路:
- 1.停止应用;
- 2.找测试库;
- 3.先恢复昨晚全量备份的数据;
- 4.截取全量备份后yinzhengjie.k8s被误删除时间点的oplog日志;
- 5.将截取的数据恢复到测试库;
- 6.将误删除表导出,恢复到生产库;
6.2 故障恢复案例落地
1.写入测试数据
yinzhengjie-mongodb-rs [direct: primary] test> use yinzhengjie
switched to db yinzhengjie
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> for(i=0;i<500;i++){db.k8s.insertOne({tid: i, name: "杰哥讲运维"+i,age: 18,date: new Date()})}
{
acknowledged: true,
insertedId: ObjectId('683f0fd8bd8be3f3b001356e')
}
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.k8s.countDocuments()
500
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
2.完全备份需要使用"--oplog"选项
[root@node-exporter41 ~]# mkdir /opt/oplog-backup-full
[root@node-exporter41 ~]# mongodump --oplog -o /opt/oplog-backup-full
2025-06-03T23:09:37.388+0800 writing admin.system.version to /opt/oplog-backup-full/admin/system.version.bson
2025-06-03T23:09:37.389+0800 done dumping admin.system.version (1 document)
2025-06-03T23:09:37.389+0800 writing yinzhengjie.teacher to /opt/oplog-backup-full/yinzhengjie/teacher.bson
2025-06-03T23:09:37.389+0800 writing yinzhengjie.k8s to /opt/oplog-backup-full/yinzhengjie/k8s.bson
2025-06-03T23:09:37.393+0800 done dumping yinzhengjie.k8s (500 documents)
2025-06-03T23:09:37.440+0800 done dumping yinzhengjie.teacher (36950 documents)
2025-06-03T23:09:37.442+0800 writing captured oplog to
2025-06-03T23:09:37.443+0800 dumped 1 oplog entry
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# ll /opt/oplog-backup-full
total 24
drwxr-xr-x 4 root root 4096 Jun 3 23:09 ./
drwxr-xr-x 7 root root 4096 Jun 3 23:09 ../
drwxr-xr-x 2 root root 4096 Jun 3 23:09 admin/
-rw-r--r-- 1 root root 103 Jun 3 23:09 oplog.bson
-rw-r--r-- 1 root root 50 Jun 3 23:09 prelude.json
drwxr-xr-x 2 root root 4096 Jun 3 23:09 yinzhengjie/
[root@node-exporter41 ~]#
3.模拟完全备份后的数据变化
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> for(i=0;i<3000;i++){db.k8s.insertOne({tid: i, name: "杰哥讲运维"+i,age: 20,date: new Date()})}
{
acknowledged: true,
insertedId: ObjectId('683f106cbd8be3f3b0014126')
}
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.k8s.countDocuments()
3500
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> for(i=0;i<200;i++){db.docker.insertOne({tid: i, name: "杰哥讲运维"+i,age: 20,date: new Date()})}
{
acknowledged: true,
insertedId: ObjectId('683f10b3bd8be3f3b00141ee')
}
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.docker.countDocuments()
200
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
docker
k8s
teacher
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
4.模拟10:00误删除yinzhengjie库中的k8s表
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
docker
k8s
teacher
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> db.k8s.drop()
true
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
docker
teacher
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie>
5.备份当前的oplog.rs表(表示备份了最新的oplog日志)
[root@node-exporter41 ~]# mongodump -d local -c oplog.rs -o /opt/oplog-backup-increase
2025-06-03T23:15:40.944+0800 writing local.oplog.rs to /opt/oplog-backup-increase/local/oplog.rs.bson
2025-06-03T23:15:41.474+0800 done dumping local.oplog.rs (259717 documents)
[root@node-exporter41 ~]#
[root@node-exporter41 ~]# tree /opt/oplog-backup-increase
/opt/oplog-backup-increase
└── local
├── oplog.rs.bson
├── oplog.rs.metadata.json
└── prelude.json
1 directory, 3 files
[root@node-exporter41 ~]#
6.将备份下来的oplog的bson文件,覆盖完全备份的oplog.bson文件,用来还原
[root@node-exporter41 ~]# cp /opt/oplog-backup-increase/local/oplog.rs.bson /opt/oplog-backup-full/oplog.bson
[root@node-exporter41 ~]#
7.查看local库的oplog.rs表获取误删除k8s的时间戳
yinzhengjie-mongodb-rs [direct: primary] test> use local
switched to db local
yinzhengjie-mongodb-rs [direct: primary] local> db.oplog.rs.find({op:"c"}).pretty()
...
yinzhengjie-mongodb-rs [direct: primary] local> db.oplog.rs.find({ns:"yinzhengjie.k8s",op:"d"}).pretty() # 发现执行该命令不太行!
yinzhengjie-mongodb-rs [direct: primary] local> db.oplog.rs.find({op:"c"}).pretty() # 该命令记录太多了。
...
{
lsid: {
id: UUID('84b36b9b-e7f7-46cb-b04c-890cd75f1bea'),
uid: Binary.createFromBase64('47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=', 0)
},
txnNumber: Long('160'),
op: 'i',
ns: 'yinzhengjie.k8s',
ui: UUID('a01d4363-a650-4804-92ac-def3547efe5b'),
o: {
_id: ObjectId('683f0fd7bd8be3f3b001341a'),
tid: 159,
name: '杰哥讲运维159',
age: 18,
date: ISODate('2025-06-03T15:08:07.204Z')
},
o2: { _id: ObjectId('683f0fd7bd8be3f3b001341a') },
stmtId: 0,
ts: Timestamp({ t: 1748963287, i: 43 }), # 思路就是找到删除的记录并记录时间戳!
t: Long('1'),
v: Long('2'),
wall: ISODate('2025-06-03T15:08:07.206Z'),
prevOpTime: { ts: Timestamp({ t: 0, i: 0 }), t: Long('-1') }
}
8.利用oplog恢复备份至误删除时间点
mongorestore --oplogReplay --oplogLimit "1748963287:43" --drop /opt/yinzhengjie-oplog-backup/
9.验证是否恢复
yinzhengjie-mongodb-rs [direct: primary] yinzhengjie> show tables
本文来自博客园,作者:尹正杰,转载请注明原文链接:https://www.cnblogs.com/yinzhengjie/p/18909331,个人微信: "JasonYin2020"(添加时请备注来源及意图备注,有偿付费)
当你的才华还撑不起你的野心的时候,你就应该静下心来学习。当你的能力还驾驭不了你的目标的时候,你就应该沉下心来历练。问问自己,想要怎样的人生。