官方参考文档: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

至此,备份脚本测试完毕。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐