介绍
定期数据库备份是防止意外数据丢失事件的关键步骤。 通常,备份有两大类:文件系统级(“物理”)备份和逻辑备份。
文件系统级备份涉及在某个时间点快照底层数据文件,并允许数据库使用快照文件中捕获的状态完全恢复。 它们有助于快速备份大型数据库,特别是与LVM快照等文件系统快照或Digital Storage Ocean Storage Snapshots块存储卷快照结合使用时 。
逻辑备份涉及使用工具(例如mongodump
或pg_dump
)将数据库中的数据导出到备份文件中,然后使用相应的恢复工具(例如mongorestore
或pg_restore
)恢复mongorestore
。 它们可以精确地控制要备份和还原的数据,并且备份通常可以跨数据库版本和安装进行移植。 由于逻辑备份工具会读取所有通过内存备份的数据,因此它们可能会很慢并且会为特别大的数据库带来不小的额外负载。
设计有效的备份和恢复策略通常涉及以恢复速度,数据完整性和备份覆盖率来平衡性能影响,实施成本和数据存储成本。 最佳解决方案将取决于您的恢复点和时间目标以及数据库规模和体系结构。
在本指南中,我们将演示如何使用mongodump
(一种内置的逻辑备份工具)备份MongoDB数据库。 然后,我们将演示如何压缩并将生成的序列化数据备份文件上传到高度冗余的对象库 。 我们还将演示如何使用Bash和cron
定期安排备份和上传操作,最后以示例数据恢复方案结束。
在本教程结束时,您将实施可扩展的自动备份策略框架,使您可以在应用程序遭受数据丢失时快速恢复。 对于中小型数据库,使用mongodump
逻辑备份可以对要备份和恢复的数据进行细化控制。 在DigitalOcean Spaces中存储这些压缩备份存档可确保它们在持久对象存储中随时可用,以便在出现数据丢失事件时保护您的应用程序数据并快速恢复。
注意:使用mongodump
工具时可能会有一些性能影响,特别是在高负载数据库上。 您应首先使用带有模拟加载的非生产数据库来测试此过程,以验证此方法是否适用于您的生产部署。
先决条件
在开始使用本指南之前,请确保您具有以下可用的先决条件:
- 具有sudo权限的非root用户的Ubuntu 16.04 Droplet,详情请参阅初始服务器设置与Ubuntu 16.04
- 正在运行的MongoDB 3.2+安装,详见如何在Ubuntu 16.04上安装MongoDB
- DigitalOcean空间和一组API凭证,详见如何创建DigitalOcean空间和API密钥 。
-
s3cmd
命令行文件传输客户端(2.X)按照如何使用Logrotate和S3cmd将日志归档到Ubuntu 16.04上的对象存储的第1步中的详细说明安装 -
s3cmd
配置为访问您的空间,详见
一旦你登录到Droplet,启动并运行MongoDB并创建了你的Space,你就可以开始了。
第1步 - 插入测试数据
如果您从一个干净的MongoDB安装开始并且尚未存储任何数据,则应首先将一些示例数据插入虚拟restaurants
集合中以用于测试目的。 如果您的数据库中已存有一些收藏和文档,请随时跳过此步骤并继续执行第2步 。
首先,使用MongoDB shell连接到正在运行的数据库:
mongo
你会看到下面的Mongo shell提示符:
MongoDB shell version: 3.2.19
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
Server has startup warnings:
2018-04-11T20:30:57.320+0000 I CONTROL [initandlisten]
2018-04-11T20:30:57.320+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2018-04-11T20:30:57.320+0000 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2018-04-11T20:30:57.320+0000 I CONTROL [initandlisten]
>
默认情况下,shell连接到test
数据库。
让我们列出test
数据库中存在的集合:
show collections
由于我们还没有向数据库中插入任何内容,因此没有集合,并且我们被带回到没有输出的提示。
让我们将文档插入虚拟restaurants
集合中,该集合将自动创建(因为它尚不存在):
db.restaurants.insert({'name': 'Pizzeria Sammy'})
您将看到以下输出:
OutputWriteResult({ "nInserted" : 1 })
这表示插入操作成功。
让我们再次列出集合:
show collections
我们现在看到我们新创建的restaurants
系列:
Outputrestaurants
要退出MongoDB shell,请按CTRL
+ D
现在我们已经在数据库中存储了一些示例数据,我们已经准备好进行备份。
第2步 - 使用mongodump
备份MongoDB数据
现在我们将使用内置的mongodump
实用程序将整个MongoDB数据库备份(或“转储”)为压缩的归档文件。
首先,我们创建一个名为backup
的临时目录来存储由mongodump
创建的mongodump
:
mkdir backup
现在,让我们将这个MongoDB实例中的test
数据库备份到名为test_dump.gz
的压缩归档文件中。 如果您的实例包含其他数据库,则可以在--db
标志后替换另一个数据库名称进行test
。 您还可以省略--db
标志来备份MongoDB实例中的所有数据库。
注意:以下命令应该从终端运行而不是 Mongo shell运行。
mongodump --db test --archive=./backup/test_dump.gz --gzip
在这里,我们使用--archive
标志来指定我们希望将所有数据保存到单个归档文件(其位置由archive
参数指定),并使用--gzip
标志来指定我们想要的压缩此文件。 另外,您可以选择使用--collection
或--query
标志来选择要归档的给定集合或查询。 要了解更多关于这些标志的信息,请参考mongodump
文档 。
运行dump命令后,您将看到以下输出:
Output2018-04-13T16:29:32.191+0000 writing test.restaurants to archive './backup/test_dump.gz'
2018-04-13T16:29:32.192+0000 done dumping test.restaurants (1 document)
这表明我们的测试数据已成功被转储。
在下一步中,我们将把这个备份存档上传到对象存储。
第3步 - 将备份存档上传到DigitalOcean Spaces
要将此存档上传到我们的DigitalOcean Space,我们需要使用我们在安装和配置的s3cmd
工具。
我们将首先测试我们的s3cmd
配置并尝试访问我们的备份空间。 在本教程中,我们将使用mongo-backup-demo
作为空间名称,但是您应该填写空间的实际名称:
s3cmd info s3://mongo-backup-demo/
您将看到以下输出:
Outputs3://mongo-backup-demo/ (bucket):
Location: nyc3
Payer: BucketOwner
Expiration Rule: none
Policy: none
CORS: none
ACL: 3587522: FULL_CONTROL
这表示连接成功, s3cmd
可以将对象传送到空间。
让我们使用put
命令将我们在第2步中创建的存档传输到我们的空间:
s3cmd put ./backup/test_dump.gz s3://mongo-backup-demo/
你会看到一些文件传输输出:
Outputupload: './backup/test_dump.gz' -> 's3://mongo-backup-demo/test_dump.gz' [1 of 1]
297 of 297 100% in 0s 25.28 kB/s done
一旦传输完成,我们将通过列出空间内容来验证文件是否已成功传输到我们的空间:
s3cmd ls s3://mongo-backup-demo/
您应该看到备份存档文件:
Output2018-04-13 20:39 297 s3://mongo-backup-demo/test_dump.gz
此时,您已成功备份test
MongoDB数据库并将备份存档传输到您的DigitalOcean Space。
在下一节中,我们将介绍如何使用Bash编写上述过程的脚本,以便我们可以使用cron
来调度它。
第4步 - 创建和测试备份脚本
现在我们已经将MongoDB数据库备份到一个压缩的存档文件并将该文件传输到我们的空间,我们可以将这些手动步骤合并到一个Bash脚本中。
创建备份脚本
我们将首先编写一个结合了mongodump
和mongodump
s3cmd put
命令的脚本,并添加一些额外的铃声和哨音,如某些日志记录(使用echo
s)。
在首选的文本编辑器中打开一个空白文件(这里我们将使用nano
):
nano backup_mongo.sh
粘贴以下代码片段,确保更新相关值以引用您自己的空间,数据库和文件名。 我们将调用文件backup_mongo.sh
,但是您可以根据需要命名该文件。 您也可以在本节最后找到完整的脚本。
让我们一块一块地看看这个脚本:
#!/bin/bash
set -e
...
在这里, #!/bin/bash
通知shell将该脚本解释为Bash代码。 如果任何脚本命令失败, set -e
告诉解释器立即退出。
...
SPACE_NAME=mongo-backup-demo
BACKUP_NAME=$(date +%y%m%d_%H%M%S).gz
DB=test
...
在本节中,我们将设置三个我们稍后会用到的变量:
-
SPACE_NAME
:我们上传备份文件的DigitalOcean空间的名称 -
BACKUP_NAME
:备份档案的名称。 在这里,我们将其设置为基本的日期时间字符串。 -
DB
:指定脚本将备份哪个MongoDB数据库。 如果您要备份整个MongoDB实例(所有数据库),则不会使用此变量。
...
date
echo "Backing up MongoDB database to DigitalOcean Space: $SPACE_NAME"
echo "Dumping MongoDB $DB database to compressed archive"
mongodump --db $DB --archive=$HOME/backup/tmp_dump.gz --gzip
echo "Copying compressed archive to DigitalOcean Space: $SPACE_NAME"
s3cmd put $HOME/backup/tmp_dump.gz s3://$SPACE_NAME/$BACKUP_NAME
...
然后我们打印日期和时间(用于记录目的),并通过运行我们上面测试的mongodump
命令开始备份。 我们再次将备份存档保存到~/backup/
。
接下来我们使用s3cmd
将该归档复制到由这两个SPACE_NAME
和BACKUP_NAME
变量指定的位置。 例如,如果我们的空间名称是mongo-backup-demo
,并且当前日期和时间是2018/04/12 12:42:21
,则备份将被命名为180412_124221.gz
并且它将被保存到mongo-backup-demo
空间。
...
echo "Cleaning up compressed archive"
rm $HOME/backup/tmp_dump.gz
echo 'Backup complete!'
在这里,我们将备份存档从~/backup
目录中删除,因为我们已经成功将其复制到了我们的空间,并且最终输出显示备份已完成。
将所有这些代码片段合并后,完整的脚本应如下所示:
#!/bin/bash
set -e
SPACE_NAME=mongo-backup-demo
BACKUP_NAME=$(date +%y%m%d_%H%M%S).gz
DB=test
date
echo "Backing up MongoDB database to DigitalOcean Space: $SPACE_NAME"
echo "Dumping MongoDB $DB database to compressed archive"
mongodump --db $DB --archive=$HOME/backup/tmp_dump.gz --gzip
echo "Copying compressed archive to DigitalOcean Space: $SPACE_NAME"
s3cmd put $HOME/backup/tmp_dump.gz s3://$SPACE_NAME/$BACKUP_NAME
echo "Cleaning up compressed archive"
rm $HOME/backup/tmp_dump.gz
echo 'Backup complete!'
完成后务必保存此文件。
接下来,我们将测试这个脚本来验证所有子命令的工作。
测试备份脚本
让我们快速运行backup_mongo.sh
脚本。
首先,使脚本可执行:
chmod +x backup_mongo.sh
现在,运行脚本:
./backup_mongo.sh
您将看到以下输出:
OutputMon Apr 16 22:20:26 UTC 2018
Backing up MongoDB database to DigitalOcean Space: mongo-backup-demo
Dumping MongoDB test database to compressed archive
2018-04-16T22:20:26.664+0000 writing test.restaurants to archive '/home/sammy/backup/tmp_dump.gz'
2018-04-16T22:20:26.671+0000 done dumping test.restaurants (1 document)
Copying compressed archive to DigitalOcean Space: mongo-backup-demo
upload: '/home/sammy/backup/tmp_dump.gz' -> 's3://mongo-backup-demo/180416_222026.gz' [1 of 1]
297 of 297 100% in 0s 3.47 kB/s done
Cleaning up compressed archive
Backup complete!
我们已经成功创建了一个备份shell脚本,现在可以继续使用cron
来安排它。
第5步 - 使用Cron安排每日备份
要计划夜间运行备份脚本,我们将使用cron
,一种内置于类Unix操作系统的作业调度实用程序。
首先,我们将创建一个目录来存储备份脚本的日志。 接下来,我们将备份脚本添加到crontab( cron
的配置文件),以便cron
安排它每晚运行。 由于cron
支持任何常规频率,因此您可以选择安排每周或每月备份。
创建日志目录
让我们创建一个目录来存储备份脚本的日志文件。 这些日志将允许我们定期检查备份脚本以确保一切正常,并且在某些命令失败时进行调试。
在/var/log
创建一个mongo_backup
子目录(按照约定用于日志记录):
sudo mkdir /var/log/mongo_backup
现在,使该目录可写入我们的Unix用户。 在这种情况下,我们的用户名是sammy ,但您应该使用sudo权限的相关非root用户名作为您的服务器。
sudo chown sammy:sammy /var/log/mongo_backup
我们的Unix用户sammy现在可以写入/var/log/mongo_backup
。 由于cronjob将以sammy身份运行,因此现在可以将其日志文件写入此目录。
让我们创建计划的cronjob。
创建Cronjob
要创建cronjob,我们将编辑包含调度作业列表的文件,称为“crontab”。 请注意,有多个crontabs,每个用户一个,以及/etc/crontab
的全系统/etc/crontab
。 在本教程中,我们将以用户sammy的身份运行备份脚本; 根据您的使用情况,您可以选择从系统范围的crontab运行它。
打开crontab进行编辑:
crontab -e
你会看到下面的菜单,让你选择你喜欢的文本编辑器:
Outputno crontab for sammy - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]: no crontab for sammy - using an empty one
选择你喜欢的编辑器; 选择nano
输入2
。 现在,在注释部分之后,将以下行添加到文件中:
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
0 2 * * * /home/sammy/mongo_backup.sh >>/var/log/mongo_backup/mongo_backup.log 2>&1
请确保在crontab的末尾包含尾随的换行符。 保存并关闭文件。
您将看到以下输出:
Outputno crontab for sammy - using an empty one
crontab: installing new crontab
备份脚本现在将在每天凌晨2:00运行。 stdout
和stderr
(输出和错误流)将被管道化并附加到我们前面创建的日志目录中的一个名为mongo_backup.log
的日志文件中。
您可以更改0 2 * * *
(在cron语法的凌晨2:00每晚执行)到您想要的备份频率和时间。 要了解有关cron及其语法的更多信息,请参阅我们的教程, 了解如何使用Cron在VPS上自动执行任务 。
我们将通过快速恢复练习结束本教程,以确保我们的备份功能正常。
第6步 - 执行测试恢复
任何备份策略都应包含经过常规测试的恢复过程。 在这里,我们将快速测试从我们上传到DigitalOcean空间的压缩备份文件中的还原。
首先,我们将从我们的Space下载test_dump.gz
到我们的MongoDB Droplet的主目录:
s3cmd get s3://mongo-backup-demo/test_dump.gz
您将看到以下输出:
Outputdownload: 's3://mongo-backup-demo/test_dump.gz' -> './test_dump.gz' [1 of 1]
297 of 297 100% in 0s 1305.79 B/s done
如果您使用新的MongoDB实例开始本教程,您会记得它只包含test
数据库,而test
数据库又是我们备份的唯一数据库。
为了演示目的,我们现在放弃这个测试数据库,以便我们可以执行干净的恢复。 如果我们不执行此第一步,恢复过程将遇到原始文档,它将跳过。 在您的特定用例中,只能恢复新文档可能是可以接受的,但为了本教程的目的,我们希望明确地将完全恢复测试到一个空的数据库中。
使用mongo
shell连接到MongoDB实例:
mongo
现在, use
test
数据库,并从MongoDB实例中删除它:
use test
db.dropDatabase()
您将看到以下输出确认test
下降:
Output{ "dropped" : "test", "ok" : 1 }
现在,退出mongo
shell并执行mongorestore
命令:
mongorestore --gzip --archive=test_dump.gz --db test
在这里,我们指定源备份文件是压缩的并且是“归档文件”形式(回想一下,在调用mongodump
时我们使用了--archive
和--gzip
标志),并且我们想要恢复到test
数据库。
您将看到以下输出:
Output2018-04-16T23:10:07.317+0000 creating intents for archive
2018-04-16T23:10:07.453+0000 reading metadata for test.restaurants from archive 'test_dump.gz'
2018-04-16T23:10:07.497+0000 restoring test.restaurants from archive 'test_dump.gz'
2018-04-16T23:10:07.541+0000 restoring indexes for collection test.restaurants from metadata
2018-04-16T23:10:07.541+0000 finished restoring test.restaurants (1 document)
2018-04-16T23:10:07.541+0000 done
这表示test
恢复成功。
总之,让我们确认我们最初的restaurants
数据已成功恢复。
打开MongoDB shell并查询restaurants
集合:
db.restaurants.find()
您应该在本教程的第一步中看到我们保存的对象:
Output{ "_id" : ObjectId("5ace7614dbdf8137afe60025"), "name" : "Pizzeria Sammy" }
您现在已经成功实施并测试了此MongoDB备份策略。
结论
在本教程中,我们学习了如何实现和测试夜间逻辑MongoDB备份的策略。
本指南可以通过多种方式扩展或修改。 以下是一些快速建议:
- 根据您的恢复点目标(RPO),您可能想要增加或减少建议的备份频率以匹配您的数据恢复窗口。
- 如果备份脚本子命令失败(例如,此功能可以将电子邮件发送到定期监视的警报收件箱),则另一个有用的添加将是警报功能。
- 该脚本不处理Spaces对象删除。 您可能需要清理比6个月左右更早的备份。
- 您可能需要实施更复杂的备份轮换方案 ,具体取决于您的生产用例。
由于mongodump
过程涉及快速读取所有转储的数据,因此此备份方法最适合于中小型数据库,特别适用于部分备份,如特定的集合或结果集。 对于较大的部署,建议使用文件系统级备份。 要了解关于文件系统级别MongoDB备份的更多信息,请参阅本教程有关如何备份MongoDB使用Droplet快照 。 要了解更多关于备份MongoDB数据库的各种方法,可以参考MongoDB手册 。
本教程中介绍的解决方案利用mongodump
对备份数据覆盖进行细粒度控制,并利用DigitalOcean Spaces实现经济高效的长期数据存储。 要了解有关mongodump
备份工具的更多信息,请查阅MongoDB手册中的参考页面 。 要了解更多关于DigitalOcean Spaces的信息,您可以阅读 。