数据备份mongodump
在mongodump可执行文件的bin目录使用命令:
./mongodump -d test -o /home/joe/
有配置环境的Linux任意路径使用命令:
mongodump也可以使用-q参数增加查询条件,只导出满足条件的文档,使用命令:
mongodump -d test -c user -q "{name: 'joe'}" -o /home/joe/
注意-q参数值的标点符号,否则会报错positional arguments not allowed。
更多mongodump的参数使用./mongodump --help查看。
全库一致性备份
# /usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 --oplog --authenticationDatabase=admin -o /app/mongodb/backup/full
单库
# /usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 -d mydb --authenticationDatabase=admin -o /app/mongodb/backup/full
单表
# /usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 -d mydb -c tt --authenticationDatabase=admin -o /app/mongodb/backup/full
数据恢复mongorestore
mongorestore使用的数据文件就是mongodump备份的数据文件。使用命令如下:
mongorestore -d test /home/joe/test --drop
使用/home/joe/test路径下的BSON和JSON文件恢复数据库test,--drop参数表示如果已经存在test数据库则删除原数据库,去掉--drop则恢复数据库时与原数据库合并。
#恢复全部数据库
mongorestore -u $DB_USER -p $DB_PASS --authenticationDatabase "admin" --noIndexRestore --dir /data/mongodb_bak/mongodb_bak_now/2016_12_17/
#恢复单个数据库
mongorestore -u $DB_USER -p $DB_PASS --authenticationDatabase "admin" --noIndexRestore -d dbname --dir /data/mongodb_bak/mongodb_bak_now/2016_12_17/dbname
部分参数说明
--drop参数:恢复数据之前删除原来的数据,避免数据重复
--noIndexRestore参数:恢复数据时不创建索引
--dir参数:数据库备份目录
-d参数:后面跟要恢复的数据库
名称
#恢复全部数据库
# /usr/local/mongodb/bin/mongorestore -uroot -pabc123 --host=192.168.1.101 --port=27017 --oplogReplay --authenticationDatabase=admin --dir /app/mongodb/backup/full --drop
#恢复单个数据库
# /usr/local/mongodb/bin/mongorestore -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d mydb --dir /app/mongodb/backup/full/mydb --drop
#恢复单表
# /usr/local/mongodb/bin/mongorestore -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d mydb -c tt --dir /app/mongodb/backup/full/mydb --drop
如果使用的副本集,那么在备份的时候可以添加--oplog选项,在备份结束之后会将oplog的所有操作记录下来,得到某个时间点的快照
直接拷贝数据目录下的一切文件:
这种方式用来备份整个mongodb的数据库,不能备份单个数据库或者子集合。在拷贝过程中必须阻止数据文件发生改变。需要对数据库加锁,以防止数据写入。
db.fsyncLock()
上面的命令将阻塞写入操作,并将脏数据刷新到磁盘上,确保数据一致
然后,拷贝数据文件到备份目录上
cp -R /data/db/* /backup
文件复制完成后,对数据库进行解锁,允许写操作
db.fsyncUnlock()
注意:在执行db.fsyncLock()和db.fsyncUnlock()时,不能关闭当前的shell窗口,否则可能无法连接而需要重新启动mongod服务
恢复时,确保mongod没有运行,清空数据目录,将备份的数据拷贝到数据目录下,然后启动mongod
cp -R /backup/* /data/db/
Mongod -f mongod.conf
数据导出mongoexport
导出Json格式
导出json格式的备份文件使用命令:
mongoexport -d test -c user -o /home/joe/user.dat
导出test数据库中user集合到目录/home/joe下的user.dat文件中。查看user.dat文件发现里面的数据是Json格式的。
mongoexport也可以使用-q参数增加查询条件,只导出满足条件的文档,使用命令:
mongoexport -d test -c user -q "{name: 'joe'}" -o /home/joe/user.dat
注意-q参数值的标点符号,否则会报错 too many positional arguments。
导出csv格式
导出csv格式的备份文件使用命令:
mongoexport -d test -c user --csv -f id,name,age -o /home/joe/user.csv
导出test数据库中user集合到目录/home/joe下的user.csv文件中。-f参数用于指定只导致id和name以及age字段。因为csv是表格类型的,所以对于内嵌文档太深的数据导出效果不是很好,所以一般来说会指定某些字段导出。
数据导入mongoimport
json格式导入
mongoimport -d test -c user /home/joe/user.dat --upsert
使用备份文件/home/joe/user.dat导入数据到test数据库的user集合中,--upsert表示更新现有数据,如果不使用—upsert则导入时已经存在的文档会报_id重复,数据不再插入。也可以使用--drop删除原数据。
csv格式导入
mongoimport -d test -c user --type csv --headerline --file /home/joe/user.csv
导入/home/joe目录下的user.csv文件中的数据到test的user集合。
--headerline指明不导入第一行,csv格式的文件第一行为列名。
导出与导入
mongoexport -h 10.10.165.90 -u laxin_user -p lx_rwx_2259 -d laxin -c mpsGrouponMember -f _id,_class,grouponCode,userId,userAccessToken,userNickName,userFormId,userHeadImg,isCommander,createUser,createTime,updateTime,delFlag,pageNo,pageSize,redDescription,coupon,redTitle,couponPrice,redExpiryDate,isNewUser --csv -o /data/backup/mps_grouponMember_20180124.csv
mongoexport -h 10.10.165.90 -u laxin_user -p lx_rwx_2259 -d laxin -c mpsGroupon -f _id,_class,grouponCode,redPacketId,status,openUserId,startTime,endTime,createUser,createTime,updateTime,delFlag,pageNo,pageSize --csv -o /data/backup/mps_groupon_20180124.csv
mongoimport -d laxin -c mpsGrouponMember --type csv --headerline --ignoreBlanks --file /data/mongo/mpsGrouponMember20180126.csv
mongoimport -d laxin -c mpsGroupon --type csv --headerline --ignoreBlanks --file /data/mongo/mpsGroupon20180126.csv
基于时间点的恢复,很重要
根据point in time恢复的前提条件:
1)必须在oplog时间窗口期内有完整的数据备份;
2)最好在误操作之后就立马停止数据库的写入操作;
下面是通过冷备份+oplog进行point in time recovery的例子(例子仅供参考,实际中请根据情况来操作,过程需严谨)
第一步:首先创造点数据
[root@mydb1 ~]# /usr/local/mongodb/bin/mongod -f /app/mongodb/27017/mongodb.config
[root@mydb2 ~]# /usr/local/mongodb/bin/mongod -f /app/mongodb/27017/mongodb.config
[root@mydb3 ~]# /usr/local/mongodb/bin/mongod -f /app/mongodb/27017/mongodb.config
[root@mydb1 ~]#/usr/local/mongodb/bin/mongo 192.168.1.101:27017/admin -u root -p abc123
myrepl:PRIMARY> use test
for(var i = 0; i < 1000; i++) {
db.foo.insert({a: i});
}
第二步:更改点数据
myrepl:PRIMARY> db.foo.update({"a":999},{$set:{"a":1000}})
第三步:做一次完全备份
[root@mydb1 ~]# /usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d test -o /backup
第四步:插入一条数据
myrepl:PRIMARY> db.foo.insert({"a":2000})
第五步:删除一条数据(模拟误操作)
myrepl:PRIMARY> db.foo.remove({"a":10})
第六步:再次插入一条数据
myrepl:PRIMARY> db.foo.insert({"a":3000})
查看现在一共有多少条数据
myrepl:PRIMARY> db.foo.count()
1001
我们现在想要取消第五步操作(remove操作,假设其为误操作),但是不影响其他数据。我们先整体备份oplog(保护犯罪现场,哈哈,防止出现其他问题,有可能的话,还可以将现在的数据进行一次备份,防止如果操作失败造成的数据问题。)
/usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d local -c oplog.rs -o /tmp/oplog/
第一步:找到误操作语句的时间戳
首先需要查找出操作失误的步骤,我们根据条件来匹配查找,条件越多对于定位误操作语句越有效。一般操作的动作肯定知道,其二是操作的库和集合肯定知道,最后如果知道大概的时间点就更好了,但这些并不能保证100%能够找到误操作的语句。
myrepl:PRIMARY> use local
myrepl:PRIMARY> db.oplog.rs.find({"op":"d","ns":"test.foo"}).pretty()
{
"ts" : Timestamp(1559836080, 1),
"t" : NumberLong(3),
"h" : NumberLong("-5373986082665093822"),
"v" : 2,
"op" : "d",
"ns" : "test.foo",
"o" : {
"_id" : ObjectId("5cf934d679cf04d3bd3abd44")
}
}
第二步:找到备份的最后一条语句的操作记录的时间戳
现在已经找到了误操作的语句后,接下来就是要找出完整备份之后和删除(误操作)之前的所有操作。
[root@mydb1 ~]# /usr/local/mongodb/bin/bsondump /backup/test/foo.bson | tail -n 1
2019-06-06T23:52:42.986+0800 1000 objects found
{"_id":{"$oid":"5cf934d779cf04d3bd3ac121"},"a":1000.0}
myrepl:PRIMARY> db.oplog.rs.find({"ns":"test.foo","o2":{ "_id" : ObjectId("5cf934d779cf04d3bd3ac121") }}).pretty()
{
"ts" : Timestamp(1559835935, 1),
"t" : NumberLong(3),
"h" : NumberLong("-8364362067976944992"),
"v" : 2,
"op" : "u",
"ns" : "test.foo",
"o2" : {
"_id" : ObjectId("5cf934d779cf04d3bd3ac121")
},
"o" : {
"$set" : {
"a" : 1000
}
}
}
PS:我个人感觉使用文档去查还是精确的,操作一般无非就是insert或update,根据其文档就可以查出这条语句的最后一步操作。
第三步:根据误操作语句的时间戳和备份数据最后一条操作语句的时间戳找到这中间的所有操作语句
myrepl:PRIMARY> db.oplog.rs.find({ns:"test.foo",ts:{$lt:Timestamp(1559836080, 1),$gt:Timestamp(1559835935, 1)}}).pretty()
{
"ts" : Timestamp(1559836027, 1),
"t" : NumberLong(3),
"h" : NumberLong("-3841083599925072888"),
"v" : 2,
"op" : "i",
"ns" : "test.foo",
"o" : {
"_id" : ObjectId("5cf9357b79cf04d3bd3ac122"),
"a" : 2000
}
}
由于生产环境中会是很多操作,所以将其dump出来
[root@mydb1 ~]# /usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d local -c oplog.rs -q '{ns:"test.foo",ts:{$lt:Timestamp(1559836080, 1),$gt:Timestamp(1559835935, 1)}}' -o /tmp/restore-1
第四步:再根据误操作时的时间戳找出之后的操作语句
myrepl:PRIMARY> db.oplog.rs.find({ns:"test.foo",ts:{$gt:Timestamp(1559836080, 1)}}).pretty()
{
"ts" : Timestamp(1559836093, 1),
"t" : NumberLong(3),
"h" : NumberLong("4961491212578993526"),
"v" : 2,
"op" : "i",
"ns" : "test.foo",
"o" : {
"_id" : ObjectId("5cf935bd79cf04d3bd3ac123"),
"a" : 3000
}
}
同样将其dump出来
/usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d local -c oplog.rs -q '{ns:"test.foo",ts:{$gt:Timestamp(1559836080, 1)}}' -o /tmp/restore-2
第五步:进行数据恢复
现在有了一次完整备份加上oplog提取的操作就可以进行数据的恢复了
myrepl:PRIMARY> use test
myrepl:PRIMARY> db.user.drop()
true
myrepl:PRIMARY> db.foo.drop()
true
做前期准备,把restore-1中的oplog.rs.bson复制到完整备份目录下,名称为oplog.bson。
[root@mydb1 ~]# cp -fr /tmp/restore-1/local/oplog.rs.bson /backup/oplog.bson
[root@mydb1 backup]# ll
总用量 4
-rw-r--r-- 1 root root 109 6月 7 00:03 oplog.bson
drwxr-xr-x 2 root root 90 6月 6 23:46 test
然后使用mongorestore进行完整备份数据的恢复,并且加上--oplogReplay参数会同时把resetore-1提取的操作进行重放(恢复第四步操作)。
[root@mydb1 ~]# /usr/local/mongodb/bin/mongorestore -uroot -pabc123 --host=192.168.1.101 --port=27017 --oplogReplay --authenticationDatabase=admin --dir /backup
2019-06-07T00:05:14.793+0800 preparing collections to restore from
2019-06-07T00:05:14.794+0800 reading metadata for test.foo from /backup/test/foo.metadata.json
2019-06-07T00:05:14.816+0800 restoring test.foo from /backup/test/foo.bson
2019-06-07T00:05:14.817+0800 reading metadata for test.user from /backup/test/user.metadata.json
2019-06-07T00:05:14.860+0800 restoring test.user from /backup/test/user.bson
2019-06-07T00:05:15.037+0800 no indexes to restore
2019-06-07T00:05:15.037+0800 finished restoring test.foo (1000 documents)
2019-06-07T00:05:15.040+0800 no indexes to restore
2019-06-07T00:05:15.040+0800 finished restoring test.user (1 document)
2019-06-07T00:05:15.040+0800 replaying oplog
2019-06-07T00:05:15.042+0800 done
进入到mongodb查看数据恢复情况。
myrepl:PRIMARY> db.foo.count()
1001
myrepl::PRIMARY> db.foo.find({"a":2000})
{ "_id" : ObjectId("5cf9357b79cf04d3bd3ac122"), "a" : 2000 }
myrepl::PRIMARY> db.foo.find({"a":10})
{ "_id" : ObjectId("5cf934d679cf04d3bd3abd44"), "a" : 10 }
myrepl::PRIMARY> db.foo.find({"a":3000})
可以看出误操作之前的数据都已经恢复,只有误操作之后的数据还没有。所以接下来就可以接着来恢复误操作之后的数据(恢复第六步操作)
再重新备份一次,然后同样把restore-2中的oplog.rs.bson复制到备份目录。
[root@mydb1 ~]# mv /backup/* /tmp/
[root@mydb1 ~]# /usr/local/mongodb/bin/mongodump -uroot -pabc123 --host=192.168.1.101 --port=27017 --authenticationDatabase=admin -d test -o /backup
[root@mydb1 ~]# cp -fr /tmp/restore-2/local/oplog.rs.bson /backup/oplog.bson
然后再次使用mongorestore进行恢复。
myrepl:PRIMARY> db.user.drop()
true
myrepl:PRIMARY> db.foo.drop()
true
[root@mydb1 ~]# /usr/local/mongodb/bin/mongorestore -uroot -pabc123 --host=192.168.1.101 --port=27017 --oplogReplay --authenticationDatabase=admin --dir /backup
最后再次进入到mongo中查看误操作之后的数据是否存在。
myrepl:PRIMARY> db.foo.count()
1002
myrepl:PRIMARY> db.foo.find({"a":3000})
{ "_id" : ObjectId("5cf935bd79cf04d3bd3ac123"), "a" : 3000 }
https://www.jb51.net/article/145399.htm
http://www.mongoing.com/eshu_point_in_time_recovery
https://www.cnblogs.com/shengdimaya/p/6598280.html
https://www.jianshu.com/p/c1eee2c7b619 根据这个做的实验
/app/mongodb/scripts/fullbackup.sh
#!/bin/sh
DATE=`date +%Y%m%d`
DEL_DATE=$(date -d '-3 days' "+%Y%m%d")
HOST=192.168.1.101
PORT=27017
USER=root
PASSWORD=abc123
DATA_DIR="/app/mongodb/27017/db"
BACKUP_PATH="/app/mongodb/backup/$DATE"
LOG_FILE="/app/mongodb/backup/mongoback.log"
DEL_PATH="/app/mongodb/backup/${DEL_DATE}/"
date +%Y%m%d%H%M >>$LOG_FILE
echo "创建备份目录$BACKUP_PATH ..."
mkdir -p $BACKUP_PATH
#第一步锁表
lock()
{
echo "db.fsyncLock()"| /usr/local/mongodb/bin/mongo --host $HOST --port $PORT -u $USER -p $PASSWORD admin
}
execute()
{
lock
if [ $? -eq 0 ]; then
echo "mongodb lock successfully!" >>$LOG_FILE
else
echo "mongodb lock fail!" >>$LOG_FILE
fi
}
execute
#第二步备份
back()
{
rsync -av $DATA_DIR $BACKUP_PATH/
}
execute()
{
back
if [ $? -eq 0 ]; then
echo "mongodb back successfully!" >>$LOG_FILE
else
echo "mongodb back fail!" >>$LOG_FILE
fi
}
execute
#第三部解锁
unlock()
{
echo "db.fsyncUnlock()"| /usr/local/mongodb/bin/mongo --host $HOST --port $PORT -u $USER -p $PASSWORD admin
}
execute()
{
unlock
if [ $? -eq 0 ]; then
echo "mongodb unlock successfully!" >>$LOG_FILE
else
echo "mongodb unlock fail!" >>$LOG_FILE
fi
}
execute
#删除历史数据
rm -rf $DEL_PATH
crontab -e
#在打开的文件中输入:
0 3 * * * sh /app/mongodb/scripts/fullbackup.sh #每天凌晨3点执行备份