介绍
定期数据库备份是防止意外数据丢失事件的关键步骤。 一般来说,有两大类备份:文件系统级(“物理”)备份和逻辑备份。
文件系统级备份涉及在某个时间点对底层数据文件进行快照,并允许数据库使用快照文件中捕获的状态进行干净的恢复。 它们有助于快速备份大型数据库,尤其是与文件系统快照(例如 LVM 快照)或块存储卷快照(例如 DigitalOcean Block Storage Snapshots)结合使用时。
逻辑备份涉及使用工具(例如 mongodump
或 pg_dump
)将数据从数据库导出到备份文件,然后使用相应的恢复工具(例如 mongorestore
或 pg_restore
)。 它们提供对要备份和恢复的数据的精细控制,并且备份通常可以跨数据库版本和安装进行移植。 由于逻辑备份工具读取通过内存备份的所有数据,它们可能会很慢,并且会为特别大的数据库造成不小的额外负载。
设计有效的备份和恢复策略通常涉及在性能影响、实施成本和数据存储成本与恢复速度、数据完整性和备份覆盖率之间进行权衡。 最佳解决方案将取决于您的恢复点和时间 目标 以及数据库规模和架构。
在本指南中,我们将演示如何使用内置的逻辑备份工具 mongodump
备份 MongoDB 数据库。 然后,我们将展示如何压缩生成的序列化数据备份文件并将其上传到 DigitalOcean Spaces,这是一个高度冗余的对象存储。 我们还将展示如何使用 Bash 和 cron
定期安排备份和上传操作,最后以示例数据恢复方案结束。
在本教程结束时,您将实现可扩展自动备份策略的框架,如果您的应用程序遭受数据丢失,您可以快速恢复。 对于中小型数据库,使用 mongodump
的逻辑备份可让您对要备份和恢复的数据进行细粒度控制。 将这些压缩备份存档存储在 DigitalOcean Spaces 中可确保它们在持久对象存储中随时可用,以便在发生数据丢失事件时保护您的应用程序数据并快速恢复。
注意: 使用 mongodump
工具时可能会有一些性能影响,尤其是在高负载的数据库上。 您应该首先使用具有模拟负载的非生产数据库测试此过程,以验证此方法是否适用于您的生产部署。
先决条件
在开始使用本指南之前,请确保您具备以下先决条件:
- 具有 sudo 权限的非 root 用户的 Ubuntu 16.04 Droplet,详见 使用 Ubuntu 16.04 的初始服务器设置
- 正在运行的 MongoDB 3.2+ 安装,详见 How to Install MongoDB on Ubuntu 16.04
- 一个 DigitalOcean Space 和一组 API 凭证,详见 如何创建 DigitalOcean Space 和 API 密钥。
s3cmd
命令行文件传输客户端 (2.X) 已安装,详见 如何使用 Logrotate 和 S3cmd 在 Ubuntu 16.04 上将日志归档到对象存储的步骤 1s3cmd
配置为访问您的空间,详见 如何配置 s3cmd 2.x 以管理 DigitalOcean 空间
一旦您登录到您的 Droplet,启动并运行 MongoDB,并创建了您的空间,您就可以开始了。
第 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
创建的存档:
mkdir backup
现在,让我们将这个 MongoDB 实例中的 test
数据库备份到一个名为 test_dump.gz
的压缩存档文件中。 如果您的实例包含其他数据库,您可以在 --db
标志之后用另一个数据库名称替换 test
。 您也可以省略 --db
标志来备份 MongoDB 实例中的 all 数据库。
注意:以下命令应该从终端运行,而不是 Mongo shell。
mongodump --db test --archive=./backup/test_dump.gz --gzip
在这里,我们使用 --archive
标志来指定我们希望将所有数据保存到单个存档文件(其位置由 archive
参数指定),并且 --gzip
标志来指定我们想要压缩这个文件。 此外,您可以选择使用 --collection
或 --query
标志来选择给定的集合或查询进行归档。 要了解有关这些标志的更多信息,请参阅 mongodump
文档 。
运行转储命令后,您将看到以下输出:
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
工具,该工具是我们在 Prerequisites 中安装和配置的。
我们将首先测试我们的 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 数据库备份到一个压缩存档文件并将这个文件传输到我们的 Space,我们可以将这些手动步骤组合到一个 Bash 脚本中。
创建备份脚本
我们将首先编写一个结合 mongodump
和 s3cmd put
命令的脚本,并添加一些额外的花里胡哨,比如一些日志记录(使用 echo
s)。
在您喜欢的文本编辑器中打开一个空白文件(这里我们将使用 nano
):
nano backup_mongo.sh
粘贴以下代码片段,确保更新相关值以引用您自己的空间、数据库和文件名。 我们将文件命名为 backup_mongo.sh
,但您可以随意命名此文件。 您还可以在本节末尾找到完整的脚本。
让我们逐个浏览这个脚本:
backup_mongo.sh
#!/bin/bash set -e ...
在这里,#!/bin/bash
告诉 shell 将脚本解释为 Bash 代码。 set -e
告诉解释器在任何脚本命令失败时立即退出。
backup_mongo.sh
... 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 实例(所有数据库),则不会使用此变量。
backup_mongo.sh
... 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
空间。
backup_mongo.sh
... echo "Cleaning up compressed archive" rm $HOME/backup/tmp_dump.gz echo 'Backup complete!'
在这里,我们从 ~/backup
目录中删除备份存档,因为我们已成功将其复制到我们的空间,最终输出指示备份已完成。
组合所有这些代码片段后,完整的脚本应如下所示:
backup_mongo.sh
#!/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”。 请注意,有多个 crontab,每个用户一个,并且在 /etc/crontab
处有一个系统范围的 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
。 现在,将以下行附加到文件中,在注释掉的部分之后:
crontab -e
# For more information see the manual pages of crontab(5) and cron(8) # # m h dom mon dow command 0 2 * * * /home/sammy/backup_mongo.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
数据库,而这又是我们备份的唯一数据库。
出于演示目的,我们现在将删除此测试数据库,以便我们可以执行干净的恢复。 如果我们不执行这第一步,恢复过程将遇到原始文档,它会跳过。 在您的特定用例中,仅恢复新文档可能是可以接受的,但出于本教程的目的,我们希望明确测试完全恢复到空数据库。
使用 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 备份的更多信息,请参阅本教程 如何使用 Droplet 快照备份 MongoDB 。 想要了解更多关于备份MongoDB数据库的各种方法,可以参考MongoDB手册。
本教程中介绍的解决方案利用 mongodump
对备份数据覆盖范围进行精细控制,并利用 DigitalOcean Spaces 实现经济高效且持久的长期数据存储。 要了解有关 mongodump
备份实用程序的更多信息,请参阅 MongoDB 手册中的 参考页 。 要了解有关 DigitalOcean Spaces 的更多信息,您可以阅读 DigitalOcean Spaces 简介。