MongoDB 的完全&增量备份 (包含脚本) (生产环境可用)
此文档中的脚本主要是参考的 "东山絮柳仔" 的一篇文章:https://www.cnblogs.com/xuliuzai/p/9832333.html自己梳理了一遍他的脚本,并查阅了一些官方的文档;然后对脚本进行了一些更改,适用于自己的环境。
官方参考文档:https://docs.mongodb.com/v3.2/core/replica-set-oplog/
参考文档:https://www.cnblogs.com/xuliuzai/p/9832333.html
mongodump
官方参考文档:https://docs.mongodb.com/v3.2/reference/program/mongodump/
mongodump 备份注意点
- 会排除 local 数据库的内容
- 备份不包含索引
- 不要使用大于 2.2 版本的 mongodump 去备份小于 2.2 版本 mongodb。(mongodump 可以备份远程的数据库)。
mongodump 常用选项
--host <hostname><:port>, -h <hostname><:port>
指定要备份的数据库。如果要从副本集中备份,请指定 replSetName 和副本集成员列表:<replSetName>/<hostname1><:port>,<hostname2><:port>,<...>
。这种情况下,mongodump 默认会从 primary 读取;如果只指定了副本集成员列表,没有指定 replSetName,则 mongodump 默认会从 nearest 读取。
当然,也可以通过 --host
指定 IP 地址,--port
指定端口来连接单节点。
·
--db <database>, -d <database>
指定要备份的数据库。如果未指定,则会备份所有数据库。
·
--collection <collection>, -c <collection>
指定要备份的集合。 如果未指定,则会备份所有集合。
·
--gzip
压缩备份文件,3.2 版中的新功能。
·
--out <path>, -o <path>
指定备份路径
·
--archive <file or null>
将备份内容写入单个文件或标准输出。
如果使用了--gzip
,则 --archive
指定的文件应该以 “.gz” 结尾。例如:
mongodump --archive=test.20200202.gz --gzip --db test
注意: --out
和 --archive
不能同时使用>
·
--oplog
可以理解为开启增量备份。
此选项会创建一个名为 oplog.bson 的文件,包含 mongodump 操作期间发生的 oplog 操作。
注意: --oplog
只对全库导出有效。
·
--query <json>, -q <json>
提供一个 JSON 文档作为查询,可以限制 mongodump 输出的内容。
·
如果开启了用户密码认证。还需要使用以下选项来指定:
--username <username>, -u <username>
--password <password>, -p <password>
mongorestore
官方文档:https://docs.mongodb.com/v3.2/reference/program/mongorestore/
当 mongorestore 导入的备份数据已存在时,并不会覆盖这些数据,而是只增加不存在的数据。
mongorestore 常用选项
下面几项于 mongodump 的选项相同:
--host <hostname><:port>, -h <hostname><:port>
--db <database>, -d <database>
--collection <collection>, -c <collection>
--username <username>, -u <username>
--password <password>, -p <password>
·
--oplogReplay
还原数据库转储后,从转储目录顶层中的 oplog.bson 文件中执行 oplog 条目。
·
--gzip
从 mongodump 创建的压缩文件中还原数据
·
--oplogLimit <timestamp>
恢复数据到指定时间点。<timestamp> 格式为:
<time_t>:<ordinal>
<time_t> 是 UNIX 时代以来的秒数。
<ordinal> 代表操作日志中在指定秒内发生的操作的计数器。
oplog 的介绍
oplog (操作日志)是一个特殊的,有上限的集合(oplog.rs),存在于 local 数据集库中,该集合记录的内容是关于所有数据库写操作的日志。
注意: oplog 是滚动记录。即:空间大小固定,当空间占满时还有数据写入,就会自动删除最旧的数据。
mongodump 中的一个选项 --query <json>, -q <json>
可以限制 mongodump 备份的内容。mongorestore 中的一个选项 --oplogReplay
会在还原数据库转储后,还会从转储目录顶层中的 oplog.bson 文件中执行 oplog 条目。oplog 中又滚动记录这关于所有数据库写操作的日志。那么我们就可以通过备份 oplog 来实现增量备份。
注意: 备份 oplog 时,生成的文件名为:oplog.rs.bson,而恢复时只会从 oplog.bson 文件中执行 oplog 条目;所以,增量恢复时需要修改文件名。
·
完全备份脚本
#!/bin/bash
#############################################################################
# 参考地址:"https://www.cnblogs.com/xuliuzai/p/9917137.html" #
# 此脚本为 mongodb 的全量备份脚本,配合增量备份脚本一起使用 #
# 备份策略为:每周一次完全备份(0 4 * * 1),每天一次增量备份(30 3 * * *)。 #
#############################################################################
host='192.168.10.140'
port='27017'
sourcepath='/usr/local/mongodb/bin'
nowtime=$(date "+%Y%m%d")
#### 自动检查/创建增量备份路径 ####
if [ ! -d /data/mongodb_back/mongodb_backup_all/mongo-$port ];then
mkdir -p /data/mongodb_back/mongodb_backup_all/mongo-$port
fi
if [ ! -d /data/mongodb_back/mongodb_backup_all/log-$port ];then
mkdir -p /data/mongodb_back/mongodb_backup_all/log-$port
fi
targetpath="/data/mongodb_back/mongodb_backup_all/mongo-$port"
logpath="/data/mongodb_back/mongodb_backup_all/log-$port"
#### 备份函数 ####
start(){
$sourcepath/mongodump --host $host --port $port --oplog --gzip --out ${targetpath}/${nowtime}
}
#### 判断备份是否成功的函数 ####
execute(){
echo "=========================$(date) backup all mongodb back start ${nowtime}=========" >> ${logpath}/${nowtime}.log
start
if [ $? -eq 0 ];then
echo "The MongoDB BackUp Successfully!" >> ${logpath}/${nowtime}.log
else
echo "The MongoDB BackUp Failure" >> ${logpath}/${nowtime}.log
fi
}
execute
#### 删除7天前的备份 ####
backtime=$(date -d '-7 days' "+%Y%m%d")
if [ -d "${targetpath}/${backtime}/" ];then
rm -rf "${targetpath}/${backtime}/"
echo "=======${targetpath}/${backtime}/===删除完毕==" >> ${logpath}/${nowtime}.log
fi
echo "========================= $(date) backup all mongodb back end ${nowtime}=========" >> ${logpath}/${nowtime}.log
·
增量备份脚本
#!/bin/bash
#############################################################################
# 参考地址:"https://www.cnblogs.com/xuliuzai/p/9917137.html" #
# 此脚本为 mongodb 的增量备份脚本,配合完全备份脚本一起使用 #
# 备份策略为:每周一次完全备份(0 4 * * 1),每天一次增量备份(30 3 * * *)。 #
#############################################################################
command_linebin="/usr/local/mongodb/bin/mongo"
port="27017"
#### 自动检查/创建增量备份路径 ####
if [ ! -d "/data/mongodb_back/mongodboplog_back/mongo-$port" ];then
mkdir -p /data/mongodb_back/mongodboplog_back/mongo-$port
fi
if [ ! -d "/data/mongodb_back/mongodboplog_back/log-$port" ];then
mkdir -p /data/mongodb_back/mongodboplog_back/log-$port
fi
bkdatapath=/data/mongodb_back/mongodboplog_back/mongo-$port
bklogpath=/data/mongodb_back/mongodboplog_back/log-$port
#### 获取增量(oplog)备份的起止时间 ####、
#### 变量 DiffTime 为备份间隔,我这里是24小时+10分钟。多出来的10分钟是预估每次备份时间在10分钟以内,来确保数据的连续性 ####
logfilename=$(date -d today +"%Y%m%d")
echo "===================================Message --=MongoDB 端口为" $port "的差异备份开始,开始时间为" $(date -d today +"%Y-%m-%-d %H:%M:%S") >> $bklogpath/$logfilename.log
ParamBakEndDate=$(date +%s)
echo "Message --本次备份时间参数中的结束时间为:" $ParamBakEndDate >> $bklogpath/$logfilename.log
#DiffTime=$(expr 65 \* 60)
DiffTime=$(echo "60*60*24 + 10*60" |bc)
echo "Message --备份设置的间隔时间为:" $DiffTime >> $bklogpath/$logfilename.log
ParamBakStartDate=$(expr $ParamBakEndDate - $DiffTime)
echo "Message --本次备份时间参数中的开始时间为:" $ParamBakStartDate >> $bklogpath/$logfilename.log
####检查 oplog 中最早的一笔数据,验证此次备份的时间是否在 oplog 记录的时间范围内
bkfilename=$(date -d today +"%Y%m%d%H%M%S")
command_line="${command_linebin} localhost:$port"
opmes=$(/bin/echo "db.printReplicationInfo()" | $command_line --quiet)
echo $opmes > opdoctime$port.tmplog
opbktmplogfile=opdoctime$port.tmplog
opstartmes=$(grep "oplog first event time" $opbktmplogfile | awk -F 'CST' '{print $1}' | awk -F 'oplog first event time: ' '{print $2}' | awk -F ' GMT' '{print $1}' )
echo "Message --oplog集合记录的开始时间为:"$opstartmes >> $bklogpath/$logfilename.log
oplogRecordFirst=$(date -d "$opstartmes" +%s)
echo "Message --oplog集合记录的开始时间为:" $oplogRecordFirst >> $bklogpath/$logfilename.log
## 比较备份参数的开始时间是否在 oplog 记录的时间范围内
if [ $oplogRecordFirst -le $ParamBakStartDate ];then
echo "Message --检查设置备份时间合理。备份参数的开始时间在oplog记录的时间范围内。" >> $bklogpath/$logfilename.log
else
echo "Fatal Error --检查设置的备份时间不合理合理。备份参数的开始时间不在oplog记录的时间范围内。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。" >> $bklogpath/$logfilename.log
fi
# 执行 mongodump
/usr/local/mongodb/bin/mongodump -h localhost --port $port -d local -c oplog.rs --query '{ts:{$gte:Timestamp('$ParamBakStartDate',1),$lte:Timestamp('$ParamBakEndDate',9999)}}' -o $bkdatapath/mongodboplog$bkfilename >> $bklogpath/$logfilename.log 2>&1
#### 再次检查,防止导出 oplog 数据时间过长,而导致旧数据被更新,所以再次进行检查 ####
#### 因 oplog 的空间大小是固定的,而且数据是滚动记录的。####
#### 如果在导出期间有大量的写操作,则 oplog 中新的数据会覆盖掉旧的数据,就可能导致导出的数据不完整,无法保证增量文件间的时间连续性。 ####
#DiffTime=$(expr 61 \* 60)
DiffTime=$(echo "60*60*24 + 5*60" |bc)
ParamAfterBakRequestStartDate=$(expr $ParamBakEndDate - $DiffTime)
echo "Message --为保证备份的连续性,本次备份后,oplog中的开始时间需小于:" $ParamAfterBakRequestStartDate >> $bklogpath/$logfilename.log
opmes=$(/bin/echo "db.printReplicationInfo()" | $command_line --quiet)
echo $opmes > opdoctime$port.tmplog
opbktmplogfile=opdoctime$port.tmplog
opstartmes=$(grep "oplog first event time" $opbktmplogfile | awk -F 'CST' '{print $1}' | awk -F 'oplog first event time: ' '{print $2}' | awk -F ' GMT' '{print $1}' )
echo "Message --执行备份后,oplog集合记录的开始时间为:"$opstartmes >> $bklogpath/$logfilename.log
oplogRecordFirst=$(date -d "$opstartmes" +%s)
echo "Message --执行备份后,oplog集合记录的开始时间为[时间格式化]:" $oplogRecordFirst >> $bklogpath/$logfilename.log
##begin 比较备份参数的开始时间是否在oplog记录的时间范围内
if [ $oplogRecordFirst -le $ParamAfterBakRequestStartDate ];then
echo "Message --备份后,检查 oplo g集合中数据的开始时间,即集合中最早的一笔数据,时间不小于$ParamAfterBakRequestStartDate。这样可以保证每个增量备份含有最近一个小时的全部 op 操作,满足数据的持续完整性,逐个还原无丢失数据风险。" >> $bklogpath/$logfilename.log
else
echo "Fatal Error --备份后,检查 oplog 集合的涵盖的时间范围过小。设置的备份时间不合理,备份后的文件不能完全涵盖最近1天的数据。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。" >> $bklogpath/$logfilename.log
fi
#### 检查备份文件是否生成 ####
if [ -d "$bkdatapath/mongodboplog$bkfilename" ];then
echo "Message --检查此次备份文件已经产生.文件信息为:" $bkdatapath/mongodboplog$bkfilename >> $bklogpath/$logfilename.log
else
echo "Fatal Error --备份过程已执行,但是未检测到备份产生的文件,请检查!" >> $bklogpath/$logfilename.log
fi
#### 删除历史备份文件,保留7天,如需调整,请在持续设置
keepbaktime=$(date -d '-7 days' "+%Y%m%d%H")*
if [ -d $bkdatapath/mongodboplog$keepbaktime ];then
rm -rf $bkdatapath/mongodboplog$keepbaktime
echo "Message -- $bkdatapath/mongodboplog$keepbaktime 删除完毕" >> $bklogpath/$logfilename.log
fi
echo "============================Message --MongoDB 端口为" $port "的差异备份结束,结束时间为:" $(date -d today +"%Y%m%d%H%M%S") >> $bklogpath/$logfilename.log
·
备份脚本测试
1 同步时间为国内标准时间
ntpdate -s ntp1.aliyun.com
2 安装 mongodb,并开启副本集
安装步骤可参考前面的文档:MongoDB 副本集的部署
我这里新安装是为了重置 oplog 的初始数据的时间,方便测试。
3 登入 mongodb,并写入数据
#创建库,并写入数据(10000条数据)
MongoDB Enterprise rs0:PRIMARY> use all_back_test
MongoDB Enterprise rs0:PRIMARY> for(var i=0;i<10000;i++){db.allback.insert({"id":i,"name":"wpf","addr":"不黑","date":new Date()})}
#查看数据是否写入成功
MongoDB Enterprise rs0:PRIMARY> db.allback.count()
10000
4 全量备份
[root@mongodb111 ~]# sh /data/mongodb_back/script/mongodb_all_back.sh
5 登入 mongodb,再次写入数据
MongoDB Enterprise rs0:PRIMARY> use zeng_back_test
MongoDB Enterprise rs0:PRIMARY> for(var i=0;i<10000;i++){db.increment.insert({"id":i,"name":"wpf","addr":"真帅","date":new Date()})}
6 修改时间
由于我的备份策略为一周一次全量备份,每天一次增量备份;所以实验修改时间为后一天(再加10分钟:脚本中有说明)的时间。
#查看 oplog 信息,可以看到oplog的初始(first)时间为"2021-04-23 10:30:20"
MongoDB Enterprise rs0:PRIMARY> rs.printReplicationInfo()
configured oplog size: 10240MB
log length start to end: 288secs (0.08hrs)
oplog first event time: Fri Apr 23 2021 10:30:20 GMT+0800 (CST)
oplog last event time: Fri Apr 23 2021 10:35:08 GMT+0800 (CST)
now: Fri Apr 23 2021 10:36:52 GMT+0800 (CST)
#先修改时间为"2021-04-24 10:00:00",验证增量脚本是否正常
date -s "20210424 10:00:00"
#执行脚本
[root@mongodb111 ~]# sh /data/mongodb_back/script/mongodb_zeng_back.sh
#查看日志,发现报错。说明备份脚本中关于报错的模块正常。
[root@mongodb111 ~]# cat /data/mongodb_back/mongodboplog_back/log-27017/20210424.log
===================================Message --=MongoDB 端口为 27017 的差异备份开始,开始时间为 2021-04-24 10:00:14
Message --本次备份时间参数中的结束时间为: 1619229614
Message --备份设置的间隔时间为: 87000
Message --本次备份时间参数中的开始时间为: 1619142614
Message --oplog集合记录的开始时间为:Fri Apr 23 2021 10:30:20
Message --oplog集合记录的开始时间为: 1619145020
Fatal Error --检查设置的备份时间不合理合理。备份参数的开始时间不在oplog记录的时间范围内。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。
2021-04-24T10:00:14.662+0800 writing local.oplog.rs to
2021-04-24T10:00:14.768+0800 done dumping local.oplog.rs (20008 documents)
Message --为保证备份的连续性,本次备份后,oplog中的开始时间需小于: 1619142914
Message --执行备份后,oplog集合记录的开始时间为:Fri Apr 23 2021 10:30:20
Message --执行备份后,oplog集合记录的开始时间为[时间格式化]: 1619145020
Fatal Error --备份后,检查 oplog 集合的涵盖的时间范围过小。设置的备份时间不合理,备份后的文件不能完全涵盖最近1天的数据。请调整oplog size或调整备份频率。本次备份可以持续进行,但还原时数据完整性丢失。
Message --检查此次备份文件已经产生.文件信息为: /data/mongodb_back/mongodboplog_back/mongo-27017/mongodboplog20210424100014
============================Message --MongoDB 端口为 27017 的差异备份结束,结束时间为: 20210424100014
#删除或移动错误的增量备份
[root@mongodb111 ~]# mv /data/mongodb_back/mongodboplog_back{,.bak}
#修改时间为正确的时间:"2021-04-24 11:41:00"
date -s "20210424 10:41:00"
7 增量备份
#执行脚本
[root@mongodb111 ~]# sh /data/mongodb_back/script/mongodb_zeng_back.sh
#查看日志,发现成功。说明备份脚本都正常。
[root@mongodb111 ~]# cat /data/mongodb_back/mongodboplog_back/log-27017/20210424.log
===================================Message --=MongoDB 端口为 27017 的差异备份开始,开始时间为 2021-04-24 10:41:27
Message --本次备份时间参数中的结束时间为: 1619232087
Message --备份设置的间隔时间为: 87000
Message --本次备份时间参数中的开始时间为: 1619145087
Message --oplog集合记录的开始时间为:Fri Apr 23 2021 10:30:20
Message --oplog集合记录的开始时间为: 1619145020
Message --检查设置备份时间合理。备份参数的开始时间在oplog记录的时间范围内。
2021-04-24T10:41:27.543+0800 writing local.oplog.rs to
2021-04-24T10:41:27.651+0800 done dumping local.oplog.rs (20008 documents)
Message --为保证备份的连续性,本次备份后,oplog中的开始时间需小于: 1619145387
Message --执行备份后,oplog集合记录的开始时间为:Fri Apr 23 2021 10:30:20
Message --执行备份后,oplog集合记录的开始时间为[时间格式化]: 1619145020
Message --备份后,检查 oplo g集合中数据的开始时间,即集合中最早的一笔数据,时间不小于1619145387。这样可以保证每个增量备份含有最近一个小时的全部 op 操作,满足数据的持续完整性,逐个还原无丢失数据风险。
Message --检查此次备份文件已经产生.文件信息为: /data/mongodb_back/mongodboplog_back/mongo-27017/mongodboplog20210424104127
============================Message --MongoDB 端口为 27017 的差异备份结束,结束时间为: 20210424104127
8 登入 mongodb,删除数据
MongoDB Enterprise rs0:PRIMARY> use zeng_back_test
switched to db zeng_back_test
MongoDB Enterprise rs0:PRIMARY> db.dropDatabase()
{ "dropped" : "zeng_back_test", "ok" : 1 }
MongoDB Enterprise rs0:PRIMARY> use all_back_test
switched to db all_back_test
MongoDB Enterprise rs0:PRIMARY> db.dropDatabase()
{ "dropped" : "all_back_test", "ok" : 1 }
MongoDB Enterprise rs0:PRIMARY> show dbs
local 0.001GB
9 恢复全量备份的数据
[root@mongodb111 ~]# mongorestore -h 192.168.10.140 -p port --oplogReplay --gzip /data/mongodb_back/mongodb_backup_all/mongo-27017/20210423/
2021-04-24T10:46:16.107+0800 building a list of dbs and collections to restore from /data/mongodb_back/mongodb_backup_all/mongo-27017/20210423 dir
2021-04-24T10:46:16.108+0800 reading metadata for all_back_test.allback from /data/mongodb_back/mongodb_backup_all/mongo-27017/20210423/all_back_test/allback.metadata.json.gz
2021-04-24T10:46:16.112+0800 restoring all_back_test.allback from /data/mongodb_back/mongodb_backup_all/mongo-27017/20210423/all_back_test/allback.bson.gz
2021-04-24T10:46:16.466+0800 restoring indexes for collection all_back_test.allback from metadata
2021-04-24T10:46:16.468+0800 finished restoring all_back_test.allback (10000 documents)
2021-04-24T10:46:16.468+0800 replaying oplog
2021-04-24T10:46:16.468+0800 done
#登入 mongodb 查看,发现恢复成功
MongoDB Enterprise rs0:PRIMARY> show dbs
all_back_test 0.000GB
local 0.001GB
MongoDB Enterprise rs0:PRIMARY> use all_back_test
switched to db all_back_test
MongoDB Enterprise rs0:PRIMARY> db.allback.count()
10000
10 恢复增量备份的数据
#更改 oplog.rs.bson 为 oplog.bson。因为 mongorestore 恢复值识别 oplog.bson
[root@mongodb111 local]# cd /data/mongodb_back/mongodboplog_back/mongo-27017/mongodboplog20210424104127/local
[root@mongodb111 local]# mv oplog.rs.bson oplog.bson
#恢复增量备份数据
[root@mongodb111 ~]# mongorestore -h 192.168.10.140 -p port --oplogReplay /data/mongodb_back/mongodboplog_back/mongo-27017/mongodboplog20210424104127/local
2021-04-24T10:50:30.582+0800 building a list of dbs and collections to restore from /data/mongodb_back/mongodboplog_back/mongo-27017/mongodboplog20210424104127/local dir
2021-04-24T10:50:30.582+0800 don't know what to do with file "/data/mongodb_back/mongodboplog_back/mongo-27017/mongodboplog20210424104127/local/oplog.rs.metadata.json", skipping...
2021-04-24T10:50:30.582+0800 replaying oplog
2021-04-24T10:50:33.583+0800 oplog 765KB
2021-04-24T10:50:36.583+0800 oplog 1.27MB
2021-04-24T10:50:39.584+0800 oplog 1.92MB
2021-04-24T10:50:42.583+0800 oplog 2.61MB
2021-04-24T10:50:45.239+0800 oplog 3.23MB
2021-04-24T10:50:45.239+0800 done
#登入 mongodb 查看,发现成功
MongoDB Enterprise rs0:PRIMARY> show dbs
all_back_test 0.000GB
local 0.003GB
zeng_back_test 0.000GB
MongoDB Enterprise rs0:PRIMARY> use zeng_back_test
switched to db zeng_back_test
MongoDB Enterprise rs0:PRIMARY> db.increment.count()
10000
至此,备份脚本测试完毕。
更多推荐
所有评论(0)