方法一:通过 oplog 恢复

1.1 MongoDB的常用命令

mongoexport / mongoimport
mongodump  / mongorestore

     有以上两组命令在备份与恢复中进行使用。

如果部署的是 MongoDB 复制集,这时还有一线希望,可以通过 oplog
来尽可能的恢复数据;MongoDB 复制集的每一条修改操作都会记录一条
oplog,所以当数据库被误删后,可以通过重放现有的oplog来「尽可能的恢复数据」。前不久遇到的一个用户,运气非常好,数据库是最近才创建的,所有的操作都还保留在oplog里,所以用户通过oplog把所有误删的数据都找回了。

1.1.1 导出工具mongoexport

Mongodb中的mongoexport工具可以把一个collection导出成JSON格式或CSV格式的文件。可以通过参数指定导出的数据项,也可以根据指定的条件导出数据。

   该命令的参数如下:

参数

参数说明

-h

指明数据库宿主机的IP

-u

指明数据库的用户名

-p

指明数据库的密码

-d

指明数据库的名字

-c

指明collection的名字

-f

指明要导出那些列

-o

指明到要导出的文件名

-q

指明导出数据的过滤条件

–type

指定文件类型

–authenticationDatabase

验证数据的名称

mongoexport备份实践

备份app库下的vast集合

mongoexport -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d app -c vast -o /home/mongod/backup/vasts.dat

注:备份文件的名字可以自定义,默认导出了JSON格式的数据。

导出CSV格式的数据

mongoexport -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -d app -c vast --type=csv -f id,name -o /home/mongod/backup/vast_csv.dat

通过 oplog
恢复数据的流程非常简单,只需要把oplog集合通过mongodump导出,然后通过mongorestore
的 oplogReplay 模式重放一下。

1.1.2 导入工具mongoimport

  Mongodb中的mongoimport工具可以把一个特定格式文件中的内容导入到指定的collection中。该工具可以导入JSON格式数据,也可以导入CSV格式数据。

该命令的参数如下:   

参数

参数说明

-h

指明数据库宿主机的IP

-u

指明数据库的用户名

-p

指明数据库的密码

-d

指明数据库的名字

-c

指明collection的名字

-f

指明要导出那些列

-o

指明到要导出的文件名

-q

指明导出数据的过滤条件

–drop

插入之前先删除原有的

–headerline

指明第一行是列名,不需要导入。

-j

同时运行的插入操作数(默认为1),并行

–authenticationDatabase

验证数据的名称

mongoimport恢复实践

将之前恢复的数据导入

mongoimport -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -d app -c vast  --drop /home/mongod/backup/vasts.dat

将之前恢复的CSV格式数据导入

mongoimport -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d app -c vast --type=csv --headerline --file vast_csv.dat

Step1: 导出 oplog 集合

1.1.3 【实验】mysql数据迁移至mongodb数据库

    mysql相关的参考文档:http://www.cnblogs.com/clsn/category/1131345.html

将mysql数据库中的mysql下的user表导出。

select user,host,password from mysql.user
into outfile '/tmp/user.csv'
fields terminated by ','
optionally enclosed by '"'
escaped by '"' 
lines terminated by '\r\n';

命令说明:

into outfile '/tmp/user.csv'  ------导出文件位置  
fields terminated by ','     ------字段间以,号分隔
optionally enclosed by '"'   ------字段用"号括起
escaped by '"'            ------字段中使用的转义符为"
lines terminated by '\r\n';  ------行以\r\n结束

查看导出内容

[mongod@MongoDB tmp]$ cat user.csv 
"root","localhost",""
"root","db02",""
"root","127.0.0.1",""
"root","::1",""
"","localhost",""
"","db02",""
"repl","10.0.0.%","*23AE809DDACAF96AF0FD78ED04B6A265E05AA257"
"mha","10.0.0.%","*F4C9AC49A736981AE2739FC2F4A1FD92B4F07929"

在mongodb中导入数据

mongoimport -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d app -c user -f user,host,password  --type=csv --file /tmp/user.csv

   查看导入的内容

[root@MongoDB tmp]# mongo --port 27017 
MongoDB shell version: 3.2.8
connecting to: 127.0.0.1:27017/test
> use app 
switched to db app
> db.user.find()
{ "_id" : ObjectId("5a53206b3b42ae4683180009"), "user" : "root\tlocalhost" }
{ "_id" : ObjectId("5a53206b3b42ae468318000a"), "user" : "root\tdb02" }
{ "_id" : ObjectId("5a53206b3b42ae468318000b"), "user" : "root\t127.0.0.1" }
{ "_id" : ObjectId("5a53206b3b42ae468318000c"), "user" : "root\t::1" }
{ "_id" : ObjectId("5a53206b3b42ae468318000d"), "user" : "localhost" }
{ "_id" : ObjectId("5a53206b3b42ae468318000e"), "user" : "db02" }
{ "_id" : ObjectId("5a53206b3b42ae468318000f"), "user" : "repl\t10.0.0.%\t*23AE809DDACAF96AF0FD78ED04B6A265E05AA257" }
{ "_id" : ObjectId("5a53206b3b42ae4683180010"), "user" : "mha\t10.0.0.%\t*F4C9AC49A736981AE2739FC2F4A1FD92B4F07929" }

     到此数据迁移完成。

mongodump -d local -c oplog.rs -d -o backupdir

1.2 mongodump/mongorestore实践

Step2: 拷贝oplog集合的数据

1.2.1 mongodump备份工具

  mongodump的参数与mongoexport的参数基本一致 

参数

参数说明

-h

指明数据库宿主机的IP

-u

指明数据库的用户名

-p

指明数据库的密码

-d

指明数据库的名字

-c

指明collection的名字

-o

指明到要导出的文件名

-q

指明导出数据的过滤条件

–authenticationDatabase

验证数据的名称

–gzip

备份时压缩

–oplog

use oplog for taking a point-in-time snapshot

mongodump参数实践

全库备份

mongodump -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -o /home/mongod/backup/full

备份test库

mongodump -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -d test -o /home/mongod/backup/

备份test库下的vast集合

mongodump -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -d test -c vast -o /home/mongod/backup/

压缩备份库

mongodump -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -d test -o /home/mongod/backup/ --gzip

压缩备份单表

mongodump -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin  -d test -c vast -o /home/mongod/backup/ --gzip
mkdir new_backupdir
cp backupdir/local/oplog.rs.bson new_backupdir/oplog.bson

1.2.2 mongorestore恢复实践

  mongorestore与mongoimport参数类似 

参数

参数说明

-h

指明数据库宿主机的IP

-u

指明数据库的用户名

-p

指明数据库的密码

-d

指明数据库的名字

-c

指明collection的名字

-o

指明到要导出的文件名

-q

指明导出数据的过滤条件

–authenticationDatabase

验证数据的名称

–gzip

备份时压缩

–oplog

use oplog for taking a point-in-time snapshot

–drop

恢复的时候把之前的集合drop掉

全库备份中恢复单库(基于之前的全库备份)

mongorestore -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d test --drop  /home/mongod/backup/full/test/

恢复test库

mongorestore -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d test /home/mongod/backup/test/

恢复test库下的vast集合

mongorestore -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d test -c vast /home/mongod/backup/test/vast.bson

–drop参数实践恢复

# 恢复单库
mongorestore -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d test --drop /home/mongod/backup/test/
# 恢复单表
mongorestore -h 10.0.0.152:27017 -uroot -proot --authenticationDatabase admin -d test -c vast --drop /home/mongod/backup/test/vast.bson

Step3: 重放oplog

1.2.3 mongoexport/mongoimport与mongodump/mongorestore的对比

 

  1. mongoexport/mongoimport导入/导出的是JSON格式,而mongodump/mongorestore导入/导出的是BSON格式。
  2. JSON可读性强但体积较大,BSON则是二进制文件,体积小但对人类几乎没有可读性。
  3. 在一些mongodb版本之间,BSON格式可能会随版本不同而有所不同,所以不同版本之间用mongodump/mongorestore可能不会成功,具体要看版本之间的兼容性。当无法使用BSON进行跨版本的数据迁移的时候,使用JSON格式即mongoexport/mongoimport是一个可选项。跨版本的mongodump/mongorestore并不推荐,实在要做请先检查文档看两个版本是否兼容(大部分时候是的)。
  4. JSON虽然具有较好的跨版本通用性,但其只保留了数据部分,不保留索引,账户等其他基础信息。使用时应该注意。

mongorestore --oplogReplay new_backupdir

1.3 MongoDB中的oplog

方法二:通过备份集恢复

1.3.1 什么是oplog

  MongoDB
的Replication是通过一个日志来存储写操作的,这个日志就叫做oplog。

  在默认情况下,oplog分配的是5%的空闲磁盘空间。通常而言,这是一种合理的设置。可以通过mongod
–oplogSize来改变oplog的日志大小。

  oplog是capped
collection,因为oplog的特点(不能太多把磁盘填满了,固定大小)需要,MongoDB才发明了capped
collection(the oplog is actually the reason capped collections were
invented). 定值大小的集合,oplogSizeMB:
2048,oplog是具有幂等性,执行过后的不会反复执行。

  值得注意的是,oplog**为replica
set或者master/slave模式专用(standalone模式运行mongodb并不推荐)。**

oplog的位置:

oplog在local库: local。oplog

master/slave 架构下:local.oplog.$main;

 

replica sets 架构下:local.oplog.rs

参数说明

$ mongodump --help
 --oplog use oplog for taking a point-in-time snapshot

  该参数的主要作用是在导出的同时生成一个oplog.bson文件,存放在你开始进行dump到dump结束之间所有的oplog。

  oplog
官方说明https://docs.mongodb.com/manual/core/replica-set-oplog/

 bet36365注册送奖金 1

  简单地说,在replica set中oplog是一个定容集合(capped
collection),它的默认大小是磁盘空间的5%(可以通过–oplogSizeMB参数修改),位于local库的db.oplog.rs,有兴趣可以看看里面到底有些什么内容。

  其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。当空间用完时新记录自动覆盖最老的记录。

  所以从时间轴上看,oplog的覆盖范围大概是这样的:

 bet36365注册送奖金 2 

  其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。想要查看当前的oplog时间窗口预计值.

sh1:PRIMARY> rs.printReplicationInfo()
configured oplog size:   2048MB   <--集合大小
log length start to end: 305451secs (84.85hrs)  <--预计窗口覆盖时间
oplog first event time:  Thu Jan 04 2018 19:39:05 GMT+0800 (CST)
oplog last event time:   Mon Jan 08 2018 08:29:56 GMT+0800 (CST)
now:                     Mon Jan 08 2018 16:33:25 GMT+0800 (CST)

  oplog有一个非常重要的特性——幂等性(idempotent)。即对一个数据集合,使用oplog中记录的操作重放时,无论被重放多少次,其结果会是一样的。

  举例来说,如果oplog中记录的是一个插入操作,并不会因为你重放了两次,数据库中就得到两条相同的记录。这是一个很重要的特性.

如果对 MongoDB 做了全量备份 +
增量备份,那么可以通过备份集及来恢复数据。备份可以是多种形式,比如:

1.3.2 oplog.bson作用

与oplog相关的参数

参数

参数说明

–oplogReplay

重放oplog.bson中的操作内容

–oplogLimit

与–oplogReplay一起使用时,可以限制重放到的时间点

  首先要明白的一个问题是数据之间互相有依赖性,比如集合A中存放了订单,集合B中存放了订单的所有明细,那么只有一个订单有完整的明细时才是正确的状态。

  假设在任意一个时间点,A和B集合的数据都是完整对应并且有意义的(对非关系型数据库要做到这点并不容易,且对于MongoDB来说这样的数据结构并非合理。但此处我们假设这个条件成立),那么如果A处于时间点x,而B处于x之后的一个时间点y时,可以想象A和B中的数据极有可能不对应而失去意义。

  mongodump的进行过程中并不会把数据库锁死以保证整个库冻结在一个固定的时间点,这在业务上常常是不允许的。所以就有了dump的最终结果中A集合是10点整的状态,而B集合则是10点零1分的状态这种情况。

  这样的备份即使恢复回去,可以想象得到的结果恐怕意义有限。

  那么上面这个oplog.bson的意义就在这里体现出来了。如果在dump数据的基础上,再重做一遍oplog中记录的所有操作,这时的数据就可以代表dump结束时那个时间点(point-in-time)的数据库状态。

  • 通过 mongodump 等工具,对数据库产生的逻辑备份
  • 拷贝 dbpath 目录产生的物理备份
  • 文件系统、卷管理等产生的快照等

1.3.3 【模拟】mongodump使用

首先我们模拟一个不断有插入操作的集合foo,

use clsn
for(var i = 0; i < 10000; i++) {
    db.clsn.insert({a: i});
}

  然后在插入过程中模拟一次mongodump并指定–oplog。

mongodump -h 10.0.0.152 --port 28021  --oplog  -o /home/mongod/backup/oplog

  注意:–oplog选项只对全库导出有效,所以不能指定-d选项。

       因为整个实例的变更操作都会集中在local库中的oplog.rs集合中。

根据上面所说,从dump开始的时间系统将记录所有的oplog到oplog.bson中,所以我们得到这些文件:

[mongod@MongoDB ~]$ ll /home/mongod/backup/oplog 
total 8
drwxrwxr-x 2 mongod mongod   4096 Jan  8 16:49 admin
drwxrwxr-x 2 mongod mongod   4096 Jan  8 16:49 clsn
-rw-rw-r-- 1 mongod mongod  77256 Jan  8 16:49 oplog.bson

查看oplog.bson中第一条和最后一条内容

[mongod@MongoDB oplog]$ bsondump oplog.bson  >/tmp/oplog.bson.tmp
[mongod@MongoDB oplog]$ head -1 /tmp/oplog.bson.tmp 
{"ts":{"$timestamp":{"t":1515401553,"i":666}},"t":{"$numberLong":"5"},"h":{"$numberLong":"5737315465472464503"},"v":2,"op":"i","ns":"clsn.clsn1","o":{"_id":{"$oid":"5a533151cc075bd0aa461327"},"a":3153.0}}
[mongod@MongoDB oplog]$ tail -1 /tmp/oplog.bson.tmp 
{"ts":{"$timestamp":{"t":1515401556,"i":34}},"t":{"$numberLong":"5"},"h":{"$numberLong":"-7438621314956315593"},"v":2,"op":"i","ns":"clsn.clsn1","o":{"_id":{"$oid":"5a533154cc075bd0aa4615de"},"a":3848.0}}

  最终dump出的数据既不是最开始的状态,也不是最后的状态,而是中间某个随机状态。这正是因为集合不断变化造成的。

  使用mongorestore来恢复

[mongod@MongoDB oplog]$ mongorestore -h 10.0.0.152 --port 28021  --oplogReplay  --drop   /home/mongod/backup/oplog
2018-01-08T16:59:18.053+0800    building a list of dbs and collections to restore from /home/mongod/backup/oplog dir
2018-01-08T16:59:18.066+0800    reading metadata for clsn.clsn from /home/mongod/backup/oplog/clsn/clsn.metadata.json
2018-01-08T16:59:18.157+0800    restoring clsn.clsn from /home/mongod/backup/oplog/clsn/clsn.bson
2018-01-08T16:59:18.178+0800    reading metadata for clsn.clsn1 from /home/mongod/backup/oplog/clsn/clsn1.metadata.json
2018-01-08T16:59:18.216+0800    restoring clsn.clsn1 from /home/mongod/backup/oplog/clsn/clsn1.bson
2018-01-08T16:59:18.669+0800    restoring indexes for collection clsn.clsn1 from metadata
2018-01-08T16:59:18.679+0800    finished restoring clsn.clsn1 (3165 documents)
2018-01-08T16:59:19.850+0800    restoring indexes for collection clsn.clsn from metadata
2018-01-08T16:59:19.851+0800    finished restoring clsn.clsn (10000 documents)
2018-01-08T16:59:19.851+0800    replaying oplog
2018-01-08T16:59:19.919+0800    done

  注意黄字体,第一句表示clsn.clsn1集合中恢复了3165个文档;第二句表示重放了oplog中的所有操作。所以理论上clsn1应该有16857个文档(3165个来自clsn.bson,剩下的来自oplog.bson)。验证一下:

sh1:PRIMARY> db.clsn1.count()
3849

  这就是带oplog的mongodump的真正作用。

从这里其实也可以看出一个问题,就是「部署了多节点的复制集,为什么还需要做数据备份?」;遇到误删数据库这种问题,dropDatabase
命令也会同步到所有的备节点,导致所有节点的数据都被删除。

1.3.4 从别处而来的oplog

oplog有两种来源:

1、mongodump时加上–oplog选项,自动生成的oplog,这种方式的oplog直接
–oplogReplay 就可以恢复

 

2、从别处而来,除了–oplog之外,人为获取的oplog

例如:

mongodump  --port 28021 -d local -c oplog.rs

  既然dump出的数据配合oplog就可以把数据库恢复到某个状态,那是不是拥有一份从某个时间点开始备份的dump数据,再加上从dump开始之后的oplog,如果oplog足够长,是不是就可以把数据库恢复到其后的任意状态了?是的!

  事实上replica
set正是依赖oplog的重放机制在工作。当secondary第一次加入replica
set时做的initial
sync就相当于是在做mongodump,此后只需要不断地同步和重放oplog.rs中的数据,就达到了secondary与primary同步的目的。

  既然oplog一直都在oplog.rs中存在,我们为什么还需要在mongodump时指定–oplog呢?需要的时候从oplog.rs中拿不就完了吗?答案是肯定的,你确实可以只dump数据,不需要oplog。

在需要的时候可以再从oplog.rs中取。但前提是oplog时间窗口必须能够覆盖dump的开始时间。

及时点恢复场景模拟

模拟生产环境

for(i=0;i<300000;i++){ db.oplog.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }

   插入数据的同时备份

mongodump -h 10.0.0.152 --port 28021  --oplog  -o /home/mongod/backup/config

    备份完成后进行次错误的操作

    db.oplog.remove({});

备份oplog.rs文件

mongodump -h 10.0.0.152 --port 28021 -d local -c oplog.rs -o  /home/mongod/backup/config/oplog

   恢复之前备份的数据

mongorestore -h 10.0.0.152 --port 28021--oplogReplay /home/mongod/backup/config

   截取oplog,找到发生误删除的时间点

bsondump oplog.rs.bson |egrep "\"op\":\"d\"\,\"ns\":\"test\.oplog\"" |head -1 
"t":1515379110,"i":1

   复制oplog到备份目录

cp  /home/mongod/backup/config/oplog/oplog.rs.bson   /home/mongod/backup/config/oplog.bson

   进行恢复,添加之前找到的误删除的点(limt)

mongorestore -h 10.0.0.152 --port 28021 --oplogReplay --oplogLimit "1515379110:1"  /home/mongod/backup/config

   
 至此一次恢复就完成了

总结

1.3.5 mongodb的备份准则

只针对replica或master/slave,满足这些准则MongoDB就可以进行point-in-time恢复操作:

 

  1. 任意两次数据备份的时间间隔(第一次备份开始到第二次备份结束)不能超过oplog时间窗口覆盖范围。
  2. 在上次数据备份的基础上,在oplog时间窗口没有滑出上次备份结束的时间点前进行完整的oplog备份。请充分考虑oplog备份需要的时间,权衡服务器空间情况确定oplog备份间隔。

实际应用中的注意事项:

 

  1. 考虑到oplog时间窗口是个变化值,请关注oplog时间窗口的具体时间。
  2. 在靠近oplog时间窗口滑动出有效时间之前必须要有足够的时间dump出需要的oplog.rs,请预留足够的时间,不要顶满时间窗口再备份。
  3. 当灾难发生时,第一件事情就是要停止数据库的写入操作,以往oplog滑出时间窗口。特别是像上述这样的remove({})操作,瞬间就会插入大量d记录从而导致oplog迅速滑出时间窗口。

分片集群的备份注意事项

1、备份什么?

  (1)configserver

  (2)每一个shard节点

2、备份需要注意什么?

  (1)元数据和真实数据要有对等性(blancer迁移的问题,会造成config和shard备份不一致)

 

  (2)不同部分备份结束时间点不一样,恢复出来的数据就是有问题的。

以上所述是小编给大家介绍的Mongodb数据库误删后的恢复方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

1.4 MongoDB监控

为什么要监控?

style=”color: #000000;”>监控及时获得应用的运行状态信息,在问题出现时及时发现。

监控什么?

style=”color: #000000;”>CPU、内存、磁盘I/O、应用程序(MongoDB)、进程监控(ps
-aux)、错误日志监控

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图