介绍
定期的数据库备份是防止意外数据丢失事件的关键步骤,一般来说,有两大类别的备份:文件系统级(物理
)备份和逻辑备份。
文件系统级的备份包括在某个时刻拍摄底层数据文件,并允许数据库使用拍摄的文件中捕获的状态清洁恢复,它们对快速备份大型数据库具有重要作用,特别是当与文件系统拍摄相结合时,如 LVM 拍摄,或阻止存储量拍摄,如 DigitalOcean Block Storage Snapshots。
逻辑备份包括使用工具(例如mongodump
或pg_dump
)将数据从数据库导出到备份文件中,然后使用相应的恢复工具(例如mongorestore
或pg_restore
)进行恢复。它们提供对何种数据进行备份和恢复的细微控制,并且备份通常可以在数据库版本和安装中移动。
设计一个有效的备份和恢复策略通常包括将性能影响、实施成本和数据存储成本与恢复速度、数据完整性和备份覆盖率进行交易,最佳解决方案将取决于您的恢复点和时间(https://en.wikipedia.org/wiki/Recovery_point_objective)以及数据库规模和架构。
在本指南中,我们将展示如何使用mongodump
,一个内置的逻辑备份工具来备份MongoDB数据库,然后我们将展示如何将结果的序列化数据备份文件压缩和上传到DigitalOcean Spaces(https://andsky.com/tech/tutorials/an-introduction-to-digitalocean-spaces),一个高度冗余的对象存储。
到本教程结束时,您将实现可扩展的自动备份策略的框架,以便在您的应用程序遭受数据损失时快速恢复。对于较小的至中型数据库,使用mongodump
的逻辑备份为您提供对哪些数据进行备份和恢复的精确控制。存储这些压缩备份档案在DigitalOcean Spaces中确保它们在可持续的对象存储中可用,以便您的应用程序数据在数据丢失事件发生时得到保护和快速恢复。
<$>[注]
**注:**在使用mongodump
工具时可能会产生一些性能影响,特别是在高负荷的数据库中。
前提条件
在您开始使用本指南之前,请确保您有以下前提条件:
- Ubuntu 16.04 Droplet 具有非根用户的 sudo 特权,如在 初始服务器设置与 Ubuntu 16.04
- 运行 MongoDB 3.2+ 安装,如在 How to Install MongoDB on Ubuntu 16.04
- A DigitalOcean Space and set of API credentials, as detailed in How To Create a DigitalOcean Space and API Key详细说明。
一旦您登录到您的Droplet,启动和运行MongoDB,并创建了您的空间,您已经准备好开始。
步骤 1 - 输入测试数据
如果你从一个干净的 MongoDB 安装开始,还没有存储任何数据,你应该先将一些样本数据插入一个愚蠢的餐厅
集合进行测试。
首先,使用 MongoDB 壳连接到运行数据库:
1mongo
您将看到以下Mongo壳提示:
1MongoDB shell version: 3.2.19
2connecting to: test
3Welcome to the MongoDB shell.
4For interactive help, type "help".
5For more comprehensive documentation, see
6 http://docs.mongodb.org/
7Questions? Try the support group
8 http://groups.google.com/group/mongodb-user
9Server has startup warnings:
102018-04-11T20:30:57.320+0000 I CONTROL [initandlisten]
112018-04-11T20:30:57.320+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
122018-04-11T20:30:57.320+0000 I CONTROL [initandlisten] ** We suggest setting it to 'never'
132018-04-11T20:30:57.320+0000 I CONTROL [initandlisten]
14>
默认情况下,壳连接到测试
数据库。
让我们列出在测试
数据库中存在的集合:
1show collections
由于我们还没有将任何东西插入到数据库中,所以没有收藏,我们被带回了提示,没有输出。
让我们将文档插入一个愚蠢的餐厅
收藏,它将自动创建(因为它还不存在):
1db.restaurants.insert({'name': 'Pizzeria Sammy'})
你会看到以下的输出:
1[secondary_label Output]
2WriteResult({ "nInserted" : 1 })
这表明插入操作成功。
让我们再次列出收藏:
1show collections
现在我们看到我们新创建的餐厅
收藏:
1[secondary_label Output]
2restaurants
要退出 MongoDB 壳,请按CTRL
+D
。
现在我们已经在数据库中存储了一些样本数据,我们已经准备好备份它。
步骤 2 – 使用mongodump
来备份 MongoDB 数据
我们现在将使用内置的mongodump
实用程序来备份(或卸载
)整个MongoDB数据库到一个压缩的档案文件。
首先,让我们创建一个名为备份
的临时目录来存储由mongodump
创建的档案:
1mkdir backup
现在,让我们将这个 MongoDB 实例中的测试
数据库备份到一个被压缩的档案文件中,名为test_dump.gz
。如果您的实例包含其他数据库,您可以在--db
旗帜之后替换另一个数据库名称为测试
。
<$>[注] **注:**下列命令应该从终端运行,而不是Mongo壳。
1mongodump --db test --archive=./backup/test_dump.gz --gzip
在这里,我们使用 - 档案
标志来指定我们希望将所有数据保存到一个单一的档案文件中(其位置由档案
参数指定),以及 - gzip
标志来指定我们希望压缩此文件。
运行 dump 命令后,您将看到以下输出:
1[secondary_label Output]
22018-04-13T16:29:32.191+0000 writing test.restaurants to archive './backup/test_dump.gz'
32018-04-13T16:29:32.192+0000 done dumping test.restaurants (1 document)
这表明我们的测试数据已被成功卸载。
在下一步中,我们将将此备份档案上传到对象存储。
步骤 3 — 将备份档案上传到 DigitalOcean Spaces
要将此档案上传到我们的DigitalOcean Space,我们需要使用s3cmd
工具,我们在前提条件
(https://andsky.com/tech/tutorials/how-to-set-up-scheduled-mongodb-backups-to-digitalocean-spaces#prerequisites)中安装和配置。
我们首先将测试我们的s3cmd
配置,并尝试访问我们的备份空间. 在本教程中,我们将使用mongo-backup-demo
作为我们的空间名称,但您应该填写您的空间的实际名称:
1s3cmd info s3://mongo-backup-demo/
你会看到以下的输出:
1[secondary_label Output]
2s3://mongo-backup-demo/ (bucket):
3 Location: nyc3
4 Payer: BucketOwner
5 Expiration Rule: none
6 Policy: none
7 CORS: none
8 ACL: 3587522: FULL_CONTROL
这表明连接成功,s3cmd
可以将对象转移到太空。
让我们使用放置
命令将我们在步骤 2 中创建的档案转移到我们的空间:
1s3cmd put ./backup/test_dump.gz s3://mongo-backup-demo/
你会看到一些文件传输的输出:
1[secondary_label Output]
2upload: './backup/test_dump.gz' -> 's3://mongo-backup-demo/test_dump.gz' [1 of 1]
3 297 of 297 100% in 0s 25.28 kB/s done
一旦转移完成,我们将通过列出空间内容来验证该文件已成功转移到我们的空间:
1s3cmd ls s3://mongo-backup-demo/
你应该看到备份档案文件:
1[secondary_label Output]
22018-04-13 20:39 297 s3://mongo-backup-demo/test_dump.gz
此时,您已成功备份测试
MongoDB 数据库并将备份档案转移到您的 DigitalOcean Space。
在下一节中,我们将讨论如何使用Bash来编写上面的程序,以便我们可以使用cron
来编程。
第4步:创建并测试备份脚本
现在,我们已经将MongoDB数据库备份为压缩的档案文件,并将该文件转移到我们的空间,我们可以将这些手动步骤合并为一个单一的Bash脚本。
创建备份脚本
我们首先会编写一个组合mongodump
和s3cmd put
命令的脚本,并添加一些额外的铃声和声,例如一些日志(使用响应
。
在您喜爱的文本编辑器中打开一个空格文件(在这里我们将使用nano
):
1nano backup_mongo.sh
插入以下代码片段,确保更新相关值以参考自己的空间,数据库和文件名称. 我们将称呼该文件为 'backup_mongo.sh',但您可以随心所欲命名此文件。
让我们通过这个脚本一部分:
1[label backup_mongo.sh]
2#!/bin/bash
3
4set -e
5...
在这里,‘#!/bin/bash’告诉壳解读脚本为Bash代码,‘set -e’告诉译者如果任何脚本命令失败,立即退出。
1[label backup_mongo.sh]
2...
3
4SPACE_NAME=mongo-backup-demo
5BACKUP_NAME=$(date +%y%m%d_%H%M%S).gz
6DB=test
7
8...
在本节中,我们设置了三种变量,我们将在以后使用:
SPACE_NAME
:我们正在上传我们的备份文件的DigitalOcean空间的名称BACKUP_NAME
:备份档案的名称 在这里,我们将其设置为一个基本的日期时间字符串DB
:指定脚本将备份哪个MongoDB数据库。
1[label backup_mongo.sh]
2...
3
4date
5echo "Backing up MongoDB database to DigitalOcean Space: $SPACE_NAME"
6
7echo "Dumping MongoDB $DB database to compressed archive"
8mongodump --db $DB --archive=$HOME/backup/tmp_dump.gz --gzip
9
10echo "Copying compressed archive to DigitalOcean Space: $SPACE_NAME"
11s3cmd put $HOME/backup/tmp_dump.gz s3://$SPACE_NAME/$BACKUP_NAME
12
13...
然后我们打印日期和时间(用于日志),并通过运行我们上面的mongodump
命令开始备份,再次将备份档案保存为~/backup/
。
接下来,我们使用s3cmd
将此档案复制到两个SPACE_NAME
和BACKUP_NAME
变量指定的位置,例如,如果我们的空间名为mongo-backup-demo
,而当前的日期和时间为2018/04/12 12:42:21
,则该备份将被命名为180412_124221.gz
,并将保存到mongo-backup-demo
空间。
1[label backup_mongo.sh]
2...
3
4echo "Cleaning up compressed archive"
5rm $HOME/backup/tmp_dump.gz
6
7echo 'Backup complete!'
在这里,我们从~/backup
目录中删除备份档案,因为我们已经成功地将其复制到我们的空间,最终的输出表示备份已经完成。
结合所有这些代码片段后,完整的脚本应该是这样的:
1[label backup_mongo.sh]
2#!/bin/bash
3
4set -e
5
6SPACE_NAME=mongo-backup-demo
7BACKUP_NAME=$(date +%y%m%d_%H%M%S).gz
8DB=test
9
10date
11echo "Backing up MongoDB database to DigitalOcean Space: $SPACE_NAME"
12
13echo "Dumping MongoDB $DB database to compressed archive"
14mongodump --db $DB --archive=$HOME/backup/tmp_dump.gz --gzip
15
16echo "Copying compressed archive to DigitalOcean Space: $SPACE_NAME"
17s3cmd put $HOME/backup/tmp_dump.gz s3://$SPACE_NAME/$BACKUP_NAME
18
19echo "Cleaning up compressed archive"
20rm $HOME/backup/tmp_dump.gz
21
22echo 'Backup complete!'
请确保在完成后保存此文件。
接下来,我们将测试此脚本,以验证所有子命令工作。
备份脚本测试
让我们快速运行备份_mongo.sh
脚本。
首先,使脚本可执行:
1chmod +x backup_mongo.sh
现在,运行脚本:
1./backup_mongo.sh
您将看到以下结果:
1[secondary_label Output]
2Mon Apr 16 22:20:26 UTC 2018
3Backing up MongoDB database to DigitalOcean Space: mongo-backup-demo
4Dumping MongoDB test database to compressed archive
52018-04-16T22:20:26.664+0000 writing test.restaurants to archive '/home/sammy/backup/tmp_dump.gz'
62018-04-16T22:20:26.671+0000 done dumping test.restaurants (1 document)
7Copying compressed archive to DigitalOcean Space: mongo-backup-demo
8upload: '/home/sammy/backup/tmp_dump.gz' -> 's3://mongo-backup-demo/180416_222026.gz' [1 of 1]
9 297 of 297 100% in 0s 3.47 kB/s done
10Cleaning up compressed archive
11Backup complete!
我们已经成功创建了一个备份壳脚本,现在可以使用cron
来计划它。
步骤 5 – 使用 Cron 安排每日备份
为了在夜间运行备份脚本,我们将使用cron
,这是一个内置于类似Unix的操作系统的任务安排工具。
首先,我们会创建一个目录来存储我们的备份脚本的日志,接下来,我们会将备份脚本添加到crontab(‘cron’的配置文件),所以‘cron’计划它在夜间运行。
创建一个Logging Directory
让我们创建一个目录来存储我们的备份脚本的日志文件. 这些日志将允许我们定期检查备份脚本,以确保一切顺利,如果某些命令失败,则调试。
在/var/log
中创建一个mongo_backup
子目录(按照用于日志登录的惯例):
1sudo mkdir /var/log/mongo_backup
在这种情况下,我们的用户名是 sammy,但您应该为您的服务器使用相关的非根用户名,具有 sudo 特权。
1sudo chown sammy:sammy /var/log/mongo_backup
我们的 Unix 用户 sammy 现在可以写到 /var/log/mongo_backup
. 由于 cronjob 将运行为 sammy,它现在可以将其日志文件写入这个目录。
让我们创建日程安排的 cronjob。
创建Cronjob
要创建 cronjob,我们将编辑包含日程表任务列表的文件,称为crontab
。 请注意,有多个crontabs,每个用户,一个系统的crontab在 /etc/crontab
. 在本教程中,我们将运行备份脚本作为我们的用户 sammy;根据您的使用情况,您可以选择从系统的crontab运行。
打开 crontab 来编辑:
1crontab -e
您将看到以下菜单,允许您选择您喜爱的文本编辑器:
1[secondary_label Output]
2no crontab for sammy - using an empty one
3
4Select an editor. To change later, run 'select-editor'.
5 1. /bin/ed
6 2. /bin/nano <---- easiest
7 3. /usr/bin/vim.basic
8 4. /usr/bin/vim.tiny
9
10Choose 1-4 [2]: no crontab for sammy - using an empty one
选择您喜爱的编辑器;选择nano
,请输入2
。
1[label crontab -e]
2# For more information see the manual pages of crontab(5) and cron(8)
3#
4# m h dom mon dow command
5
60 2 * * * /home/sammy/backup_mongo.sh >>/var/log/mongo_backup/mongo_backup.log 2>&1
请确保在 crontab 的末尾包含一个追踪的新闻行. 保存并关闭文件。
你会看到以下的输出:
1[secondary_label Output]
2no crontab for sammy - using an empty one
3crontab: installing new crontab
备份脚本现在将每天早上2点运行。stdout
和stderr
(输出和错误流)都将被导出并附加到我们之前创建的日志目录中的名为mongo_backup.log
的日志文件中。
您可以更改 0 2 * * *
(在Cron语法中晚上2点执行) 到您想要的备份频率和时间。 有关Cron及其语法的更多信息,请参阅我们的教程 如何使用Cron来自动化VPS上的任务。
我们将通过快速恢复练习结束本教程,以确保我们的备份功能。
步骤6 - 执行测试恢复
任何备份策略都应该包含一个经常测试的恢复程序. 在这里,我们将快速测试从我们上传到DigitalOcean空间的压缩备份文件的恢复。
首先,我们将从我们的空间下载 test_dump.gz
到我们的 MongoDB Droplet 主目录:
1s3cmd get s3://mongo-backup-demo/test_dump.gz
您将看到以下结果:
1[secondary_label Output]
2download: 's3://mongo-backup-demo/test_dump.gz' -> './test_dump.gz' [1 of 1]
3 297 of 297 100% in 0s 1305.79 B/s done
如果你用新鲜的 MongoDB 实例开始本教程,你会记得它只包含了测试
数据库,这反过来就是我们备份的唯一数据库。
为了演示目的,我们现在将放下这个测试数据库,以便我们可以执行清洁恢复. 如果我们不执行这个第一步,恢复程序会遇到原始文档,它会跳过。
使用mongo
壳连接到您的 MongoDB 实例:
1mongo
现在,使用``测试
数据库,然后从 MongoDB 实例中放下:
1use test
2db.dropDatabase()
您将看到以下输出确认测试
下降:
1[secondary_label Output]
2{ "dropped" : "test", "ok" : 1 }
现在,离开mongo
壳并执行mongorestore
命令:
1mongorestore --gzip --archive=test_dump.gz --db test
在这里,我们指定源备份文件是压缩和档案文件
的形式(记住,我们在调用mongodump
时使用了-档案
和-gzip
旗帜),我们希望恢复到测试
数据库。
您将看到以下结果:
1[secondary_label Output]
22018-04-16T23:10:07.317+0000 creating intents for archive
32018-04-16T23:10:07.453+0000 reading metadata for test.restaurants from archive 'test_dump.gz'
42018-04-16T23:10:07.497+0000 restoring test.restaurants from archive 'test_dump.gz'
52018-04-16T23:10:07.541+0000 restoring indexes for collection test.restaurants from metadata
62018-04-16T23:10:07.541+0000 finished restoring test.restaurants (1 document)
72018-04-16T23:10:07.541+0000 done
这表明测试
恢复成功。
最后,让我们确认我们的初始餐厅
数据已成功恢复。
打开 MongoDB 壳并查询餐厅
收藏:
1db.restaurants.find()
你应该看到我们在本教程的第一步中保存的对象:
1[secondary_label Output]
2{ "_id" : ObjectId("5ace7614dbdf8137afe60025"), "name" : "Pizzeria Sammy" }
您现在已经成功实施并测试了这个 MongoDB 备份策略。
结论
在本教程中,我们学会了如何实施和测试夜间逻辑MongoDB备份的策略。
此指南可以以多种方式扩展或修改,以下是一些快速建议:
- 取决于您的恢复点目标(RPO),您可能希望增加或减少建议的备份频率以匹配您的数据恢复窗口
- 另一个有用的添加将是一个警告函数,如果备份脚本子命令失败(例如,这个函数可能会发送电子邮件到定期监控的备份信箱)。
- 此脚本不处理空间对象删除。
由于mongodump
程序涉及快速读取所有被抛弃的数据,这种备份方法最适合小到中等大小的数据库,特别是用于特定集合或结果集等部分备份。 对于更大的部署,建议进行文件系统级备份。 有关文件系统级MongoDB备份的更多信息,请参阅本教程中的如何使用Dropplet Snapshots备份MongoDB
(LINK0)。 有关备份MongoDB数据库的各种方法的更多信息,请参阅MongoDB手册(LINK1))。
本教程中的解决方案利用mongodump
来对备份数据覆盖进行细微控制,以及DigitalOcean Spaces
来实现成本效益且可持续的长期数据存储。 有关mongodump
备份实用程序的更多信息,请参阅 MongoDB 手册中的 参考页面。