MongoDB全量备份+oplog增量备份数据恢复方案
一、MongoDB数据恢复背景简介
MongoDB 副本集的每一条修改操作都会记录一条 oplog日志,所以当数据库被误删后,可以通过重放现有的oplog来「尽可能的恢复数据」。
文章推荐:MongoDB Oplog详解
详细阅读完以上文章不难发现,oplog是有大小限制的[并且oplog文件是循环覆盖的,即当oplog写满时,最新的记录会覆盖最老的记录],可以根据自身的业务需求自定义oplog大小值。所以当业务IO读写量非常大,oplog大小设置较小时,如果误删数据,是有很大概率出现:由于oplog日志记录被覆盖而导致误删的数据无法恢复的场景。由此可见,合理配置oplog大小,可以在危机时刻最大程度的挽救业务数据的损失。
二、MongoDB数据备份mongodump与恢复mongorestore
2.1 mongodump工具用法
(1)常规用法
> mongodump -h db_host -d db_name -o db_directory -u user -p password
◆ -h 服务器IP地址
◆ -d 需要备份的数据库库名
◆ -o 备份的数据存放位置
◆ -u -p 如果有设置用户和密码,需要设置对应的用户名和密码,否则没有权限
◆ --oplog 实现热备,在备份时使用--oplog选项,会记录备份过程中的数据变化,会以oplog.bson保存下来。
【注】--oplog创建一个名为oplog.bson文件作为mongodump结果的一部分,包含了mongodump操作期间的oplog条目,实现了某个时间点的一致性快照。可用mongorestore--oplogReplay进行恢复。它的实际作用是在导出的同时生成一个oplog.bson文件,存放在你开始进行dump到dump结束之间所有的oplog。用图形来说明下oplog.bson的覆盖范围:
(2)用于比较的正则表达式
◆ $gt 大于(>)
◆ $lt 小于(<)
◆ $gte 大于等于(>=)
◆ $lte 小于等于(<=)
【注】mongodump 的--query或-q选项可以指定查询时间范围。
(3)按时间查询数据—ISODate
[root@ansible ~]# db.person.find({"timestamp":{$gte:ISODate("2021-09-26T16:00:00Z")}}).count() 【注】ISODate指的是标准时间,东八时区相差8小时
(4)按时间查询数据—Date
# 将时间戳转换为毫秒, [root@ansible ~]# date -d 2021-09-26 +%s # 2021年9月26日0时0分0秒 1632585600 # 转换完成单位为s 1632585600000 # 加三个0转换为ms # 备份大约等于某个时间范围内的oplog [root@ansible ~]# mongodump -h 192.168.0.193 --port 27017 -uroot -pUcloudcn --authenticationDatabase=admin -d local -c oplog.rs -q '{"timestamp":{$gte:Date(1632585600000)}}' -o /opt/oplogbackup
(5)按时间查询数据-Timestamp
# 备份某个时间范围内的oplog [root@ansible ~]# mongodump -h 192.168.0.193 --port 27017 -uroot -pUcloudcn --authenticationDatabase=admin -d local -c oplog.rs -q '{ts:{$lt:Timestamp(1620273590, 1),$gt:Timestamp(1620272882, 11)}}' -o /opt/oplogbackup
2.2 mongorestore工具用法
mongorestore -h <hostname><:port> -d db_name <path>
◆ --host <:port>, -h <:port>:MongoDB所在服务器地址,默认为: localhost:27017
◆ --db , -d :需要恢复的数据库实例
◆ --drop:恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!
◆ <path>:最后的一个参数,设置备份数据所在位置
◆ --dir:指定备份的目录
【注】不能同时指定 <path> 和 --dir 选项。
文章推荐:MongoDB自动备份脚本
三、MongoDB数据丢失恢复方案
备份形式会有多种:
◆ 通过mongodump等工具,对数据库进行逻辑备份(全量+增量)
◆ 通过拷贝dbpath目录产生的物理备份文件进行物理备份。
◆ 通过系统层面进行快照或者镜像进行文件系统级别备份。
【注】以上方式备份都是有实效性的,即固定时间段的数据备份,非实时。
3.1 MongoDB进行库全量备份+oplog全量备份
(1)创建dbtest库和test集合,并插入100条文档
> use dbtest switched to db dbtest > db.createCollection("testuser") { "ok" : 1 } > for(i=1;i<=100;i++){db.testuser.insert({"name": "star.gao"+i, age: i, created_time: new Date()})} WriteResult({ "nInserted" : 1 }) > db.testuser.find() { "_id" : ObjectId("60b1ab58d2535c1eec549e6d"), "name" : "star.gao1", "age" : 1, "created_time" : ISODate("2021-05-29T02:47:52.744Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e6e"), "name" : "star.gao2", "age" : 2, "created_time" : ISODate("2021-05-29T02:47:52.749Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e6f"), "name" : "star.gao3", "age" : 3, "created_time" : ISODate("2021-05-29T02:47:52.751Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e70"), "name" : "star.gao4", "age" : 4, "created_time" : ISODate("2021-05-29T02:47:52.752Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e71"), "name" : "star.gao5", "age" : 5, "created_time" : ISODate("2021-05-29T02:47:52.754Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e72"), "name" : "star.gao6", "age" : 6, "created_time" : ISODate("2021-05-29T02:47:52.755Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e73"), "name" : "star.gao7", "age" : 7, "created_time" : ISODate("2021-05-29T02:47:52.757Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e74"), "name" : "star.gao8", "age" : 8, "created_time" : ISODate("2021-05-29T02:47:52.758Z") } { "_id" : ObjectId("60b1ab58d2535c1eec549e75"), "name" : "star.gao9", "age" : 9, "created_time" : ISODate("2021-05-29T02:47:52.760Z") } …… > db.testuser.count() #插入了100条记录 100
(2)测试集合中有100条数据,测试做一个全量备份
[root@ansible ~]# mongodump --host=192.168.0.193 --port=27017 --authenticationDatabase=admin --oplog --out=/opt/fullbackup -uroot -pUcloudcn 2021-05-29T10:57:44.790+0800 writing admin.system.users to 2021-05-29T10:57:44.794+0800 done dumping admin.system.users (6 documents) 2021-05-29T10:57:44.794+0800 writing admin.system.roles to 2021-05-29T10:57:44.796+0800 done dumping admin.system.roles (1 document) 2021-05-29T10:57:44.797+0800 writing admin.system.version to 2021-05-29T10:57:44.799+0800 done dumping admin.system.version (1 document) 2021-05-29T10:57:44.802+0800 writing dbtest.testuser to 2021-05-29T10:57:44.802+0800 writing admin.tempusers to 2021-05-29T10:57:44.806+0800 done dumping admin.tempusers (6 documents) 2021-05-29T10:57:44.806+0800 done dumping dbtest.testuser (100 documents) #dbtest库testuser集合中的100条数据 2021-05-29T10:57:44.809+0800 writing captured oplog to 2021-05-29T10:57:44.812+0800 dumped 1 oplog entry
(3)继续插入10条数据
> for(i=101;i<=110;i++){db.testuser.insert({"name": "star.gao"+i, age: i, created_time: new Date()})} WriteResult({ "nInserted" : 1 }) > db.testuser.count() 110
【注】此时总计110条数据。
(4)模拟操作误删dbtest库下的testuser集合
> db.testuser.drop() true > show collections #查看当前库的集合列表
(5)备份现有的oplog.rs集合(表)
[root@ansible ~]# mongodump -h 192.168.0.193 --port 27017 -uroot -pUcloudcn --authenticationDatabase=admin -d local -c oplog.rs -o /opt/oplogbackup 2021-05-29T12:34:28.173+0800 writing local.oplog.rs to 2021-05-29T12:34:28.179+0800 done dumping local.oplog.rs (337 documents)
(6)截取oplog获取误操作时间
方法一:从oplog备份中获取误操作时间
[root@ansible ~]# bsondump /opt/oplogbackup/local/oplog.rs.bson | grep "\"op\":\"c\"" | grep "drop" {"ts":{"$timestamp":{"t":1622257440,"i":1}},"h":{"$numberLong":"161066120901963990"},"v":2,"op":"c","ns":"dbtest.$cmd","o":{"drop":"testuser"}}
获取到oplog误删除时间点位置:"ts":{"$timestamp":{"t":1622257440,"i":1}}
方法二:登录到数据库,查询误操作时间
> use local switched to db local > db.oplog.rs.count() 337 > db.oplog.rs.find({"op": "c"}).sort({"ts": -1}).limit(1) { "ts" : Timestamp(1622257440, 1), "h" : NumberLong("161066120901963990"), "v" : 2, "op" : "c", "ns" : "dbtest.$cmd", "o" : { "drop" : "testuser" } }
获取到oplog误删除时间点位置:"ts" : Timestamp(1622257440, 1)
3.2 MongoDB数据恢复到drop误操作之前的数据
(1)查看oplog恢复窗口
> rs.printReplicationInfo(); configured oplog size: 2560MB log length start to end: 337678secs (93.8hrs) #恢复窗口约93h oplog first event time: Tue May 25 2021 13:16:02 GMT+0800 (CST) oplog last event time: Sat May 29 2021 11:04:00 GMT+0800 (CST) now: Sat May 29 2021 13:24:07 GMT+0800 (CST)
【注】由于drop误操作1H前做的全备,oplog恢复窗口为93.8小时,所以可以把oplog备份出来的oplog.rs.bson文件覆盖全备时的oplog.bson文件。
(2)将oplog备份出来的oplog.rs.bson文件覆盖全备时的oplog.bson文件
[root@ansible ~]# cp /opt/oplogbackup/local/oplog.rs.bson /opt/fullbackup/oplog.bson cp: overwrite ‘/opt/fullbackup/oplog.bson’? y
(3)全量恢复数据
[root@ansible ~]# mongorestore -h 192.168.0.193 --port 27017 --oplogReplay --oplogLimit "1622257440:1" --drop /opt/fullbackup/ -uroot -pUcloudcn 2021-05-29T13:34:26.236+0800 preparing collections to restore from 2021-05-29T13:34:26.244+0800 reading metadata for dbtest.testuser from /opt/fullbackup/dbtest/testuser.metadata.json 2021-05-29T13:34:26.251+0800 reading metadata for admin.tempusers from /opt/fullbackup/admin/tempusers.metadata.json 2021-05-29T13:34:26.256+0800 restoring admin.tempusers from /opt/fullbackup/admin/tempusers.bson 2021-05-29T13:34:26.268+0800 restoring dbtest.testuser from /opt/fullbackup/dbtest/testuser.bson 2021-05-29T13:34:26.328+0800 no indexes to restore 2021-05-29T13:34:26.329+0800 finished restoring admin.tempusers (6 documents) 2021-05-29T13:34:26.332+0800 no indexes to restore 2021-05-29T13:34:26.333+0800 finished restoring dbtest.testuser (100 documents) 2021-05-29T13:34:26.333+0800 restoring users from /opt/fullbackup/admin/system.users.bson 2021-05-29T13:34:26.397+0800 restoring roles from /opt/fullbackup/admin/system.roles.bson 2021-05-29T13:34:26.423+0800 replaying oplog 2021-05-29T13:34:27.071+0800 done > show dbs admin 0.000GB dbtest 0.000GB local 0.000GB > use dbtest switched to db dbtest > show tables #testuser集合恢复成功 testuser > db.testuser.count() #集合110条文档恢复成功 110
四、关于使用oplog恢复数据场景分析
4.1 场景一:假设备份开始时间为 A 结束时间为B;等备份完成后,如果此时业务又insert或update了数据;在时间 C点,模拟误删除操作
问题分析:
如果备份开始的时间点A到误删除的时间点C 这段时间的oplog.rs的数据没有被覆盖那么就肯定能恢复出所有的数据。可以直接用oplog全量备份的oplog.rs.bson文件替换之前全量备份的产生的oplog.bson文件,然后恢复时使用--oplogReplay和--oplogLimit参数直接恢复。
恢复操作:
(1) 恢复一致性全备
[root@ansible ~]# mongorestore -h 192.168.0.193 --port 27017 --oplogReplay /opt/fullbackup/ -uroot -pUcloudcn
(2)恢复最全的oplog
[root@ansible ~]# mongorestore -h 192.168.0.193 --port 27017 --oplogReplay --oplogLimit "1622257440:1" --drop /opt/oplogbackup/local/oplog.rs.bson -uroot -pUcloudcn
4.2 场景二:如果备份开始的时间点A到你误删除的时间点C 这段时间的oplog.rs的数据被覆盖了,那么就只能先恢复你的全备,然后再从oplog.rs里面尽可能找到更多的关于这个集合的操作,然后应用,能不能全部恢复出数据,就看运气了。
挽救措施:
(1)首先停止业务,避免由于业务量大,导致把oplog 时间点B到时间点C之间的日子给覆盖了。
(2)立刻把oplog.rs集合给dump出来以便于进行时间点恢复。
作者:UStarGao
链接:https://www.starcto.com/mongodb/155.html
来源:STARCTO
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
UCloud云平台推荐
随便看看
- 2023-08-12Windows Server快速关闭自动更新功能
- 2024-09-12UCloud Centos7.x高内核降级到低内核及内核crash参数调整
- 2021-01-29MySQL复制过滤器配置方法
- 2021-05-09CURL方法测试网站响应速度
- 2021-03-27MySQL GTID全局事物标识