备份与恢复
数据备份是数据库运维中最关键的任务之一。本章介绍 MongoDB 的各种备份和恢复策略,帮助你保护数据安全。
为什么需要备份?
数据丢失可能由多种原因造成:
备份策略原则:
- 3-2-1 原则:至少保留 3 份备份,存储在 2 种不同的介质上,其中 1 份存放在异地
- 定期测试:定期验证备份是否可以正常恢复
- 自动化:使用脚本或工具自动化备份流程
备份方式对比
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| mongodump/mongorestore | 小型数据库、开发环境 | 简单易用、跨版本兼容 | 大数据量慢、影响性能 |
| 文件系统快照 | 大型数据库、生产环境 | 速度快、影响小 | 需要文件系统支持 |
| MongoDB Atlas 备份 | 云端部署 | 自动化、可恢复到任意时间点 | 仅适用于 Atlas |
| 副本集延迟节点 | 高可用环境 | 实时备份、可快速恢复 | 需要额外资源 |
mongodump 与 mongorestore
mongodump 和 mongorestore 是 MongoDB 自带的逻辑备份工具,适合中小型数据库。
mongodump - 导出数据
基本用法
# 导出所有数据库
mongodump --host localhost --port 27017 --out /backup/$(date +%Y%m%d)
# 导出指定数据库
mongodump --host localhost --port 27017 --db myapp --out /backup/$(date +%Y%m%d)
# 导出指定集合
mongodump --host localhost --port 27017 --db myapp --collection users --out /backup/$(date +%Y%m%d)
# 使用 URI 连接
mongodump --uri="mongodb://user:password@localhost:27017/myapp" --out /backup/$(date +%Y%m%d)
常用参数
| 参数 | 说明 | 示例 |
|---|---|---|
--host | MongoDB 主机 | --host localhost |
--port | MongoDB 端口 | --port 27017 |
--db | 指定数据库 | --db myapp |
--collection | 指定集合 | --collection users |
--out | 输出目录 | --out /backup |
--query | 导出符合条件的文档 | --query '{"status":"active"}' |
--gzip | 压缩输出 | --gzip |
--archive | 输出到单个归档文件 | --archive=backup.archive |
--oplog | 记录备份期间的 oplog(用于时间点恢复) | --oplog |
进阶用法
# 压缩备份
mongodump --host localhost --db myapp --gzip --out /backup/$(date +%Y%m%d)
# 输出到单个归档文件
mongodump --host localhost --db myapp --archive=/backup/myapp.archive --gzip
# 带条件导出(只导出活跃用户)
mongodump --host localhost --db myapp --collection users --query '{"status":"active"}'
# 副本集备份(带 oplog,用于时间点恢复)
mongodump --host rs0/localhost:27017,localhost:27018 --oplog --out /backup/$(date +%Y%m%d)
mongorestore - 恢复数据
基本用法
# 恢复所有数据库
mongorestore --host localhost --port 27017 /backup/20240115
# 恢复指定数据库
mongorestore --host localhost --port 27017 --db myapp /backup/20240115/myapp
# 恢复指定集合
mongorestore --host localhost --port 27017 --db myapp --collection users /backup/20240115/myapp/users.bson
# 从归档文件恢复
mongorestore --host localhost --archive=/backup/myapp.archive --gzip
常用参数
| 参数 | 说明 | 示例 |
|---|---|---|
--drop | 恢复前删除现有集合 | --drop |
--gzip | 解压 gzip 压缩的备份 | --gzip |
--archive | 从归档文件恢复 | --archive=backup.archive |
--oplogReplay | 重放 oplog(时间点恢复) | --oplogReplay |
--stopOnError | 遇到错误时停止 | --stopOnError |
--noIndexRestore | 不恢复索引 | --noIndexRestore |
进阶用法
# 恢复并删除现有数据
mongorestore --host localhost --db myapp --drop /backup/20240115/myapp
# 时间点恢复(需要备份时使用了 --oplog)
mongorestore --host localhost --oplogReplay /backup/20240115
# 只恢复数据,不恢复索引(加快恢复速度)
mongorestore --host localhost --db myapp --noIndexRestore /backup/20240115/myapp
# 恢复后重建索引
mongorestore --host localhost --db myapp /backup/20240115/myapp
文件系统快照
文件系统快照是物理备份方式,适合大型生产环境。
工作原理
使用 LVM 快照
# 1. 锁定 MongoDB(在 mongosh 中执行)
db.fsyncLock()
# 2. 创建 LVM 快照
lvcreate --size 10G --snapshot --name mongodb_snap /dev/vg0/mongodb
# 3. 解锁 MongoDB
db.fsyncUnlock()
# 4. 挂载快照进行备份
mkdir /mnt/mongodb_snap
mount /dev/vg0/mongodb_snap /mnt/mongodb_snap
# 5. 复制数据到备份位置
rsync -avz /mnt/mongodb_snap/ /backup/mongodb_$(date +%Y%m%d)/
# 6. 卸载并删除快照
umount /mnt/mongodb_snap
lvremove /dev/vg0/mongodb_snap
使用云服务商快照
# AWS EBS 快照(示例)
aws ec2 create-snapshot --volume-id vol-123456 --description "MongoDB backup"
# 阿里云快照(示例)
aliyun ecs CreateSnapshot --DiskId d-123456 --SnapshotName mongodb_backup
mongoexport 与 mongoimport
用于导出和导入 JSON 或 CSV 格式数据,适合数据迁移和部分数据导出。
mongoexport - 导出数据
# 导出为 JSON 格式
mongoexport --host localhost --db myapp --collection users --out users.json
# 导出为 CSV 格式
mongoexport --host localhost --db myapp --collection users --type=csv --fields name,email,age --out users.csv
# 导出符合条件的文档
mongoexport --host localhost --db myapp --collection users --query '{"status":"active"}' --out active_users.json
# 格式化 JSON 输出
mongoexport --host localhost --db myapp --collection users --pretty --out users_pretty.json
mongoimport - 导入数据
# 导入 JSON 文件
mongoimport --host localhost --db myapp --collection users --file users.json
# 导入 CSV 文件
mongoimport --host localhost --db myapp --collection users --type=csv --headerline --file users.csv
# 导入时忽略重复键
mongoimport --host localhost --db myapp --collection users --file users.json --mode=merge
# 导入时更新已存在的文档
mongoimport --host localhost --db myapp --collection users --file users.json --mode=upsert --upsertFields email
副本集延迟节点
通过配置延迟副本节点,实现"热备份"。
配置延迟节点
// 查看当前副本集配置
rs.conf()
// 设置延迟节点(延迟 1 小时)
var config = rs.conf()
config.members[2].priority = 0 // 不参与选举
config.members[2].hidden = true // 隐藏节点
config.members[2].slaveDelay = 3600 // 延迟 3600 秒
rs.reconfig(config)
// 验证配置
rs.conf()
从延迟节点恢复
// 1. 停止延迟节点
db.adminCommand({ shutdown: 1 })
// 2. 复制数据文件到新位置作为备份
// cp -r /data/db /backup/
// 3. 重启节点
// mongod --replSet rs0 --dbpath /data/db
MongoDB Atlas 云备份
如果使用 MongoDB Atlas,可以利用其自动备份功能。
自动备份
Atlas 提供以下备份选项:
-
Cloud Backup:基于快照的备份
- 支持时间点恢复
- 可设置保留策略
- 支持跨区域复制
-
Continuous Cloud Backup:连续备份
- 可恢复到任意时间点(最近 24-72 小时)
- 增量备份,节省空间
备份操作
# 通过 Atlas CLI 创建备份快照
atlas backups snapshots create <clusterName> --desc "Manual backup"
# 恢复快照
atlas backups restores start <clusterName> --snapshotId <snapshotId>
备份脚本示例
完整备份脚本
#!/bin/bash
# MongoDB 自动备份脚本
# 配置
MONGO_HOST="localhost"
MONGO_PORT="27017"
MONGO_USER="backup_user"
MONGO_PASS="backup_password"
BACKUP_DIR="/backup/mongodb"
DAYS_TO_KEEP=7
# 创建备份目录
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="${BACKUP_DIR}/${DATE}"
mkdir -p ${BACKUP_PATH}
# 执行备份
echo "开始备份: ${DATE}"
mongodump \
--host ${MONGO_HOST} \
--port ${MONGO_PORT} \
--username ${MONGO_USER} \
--password ${MONGO_PASS} \
--authenticationDatabase admin \
--gzip \
--out ${BACKUP_PATH}
# 检查备份是否成功
if [ $? -eq 0 ]; then
echo "备份成功: ${BACKUP_PATH}"
# 发送成功通知
# curl -X POST "webhook_url" -d "MongoDB备份成功"
else
echo "备份失败!"
# 发送失败通知
# curl -X POST "webhook_url" -d "MongoDB备份失败"
exit 1
fi
# 清理旧备份
find ${BACKUP_DIR} -type d -mtime +${DAYS_TO_KEEP} -exec rm -rf {} \;
echo "清理完成,保留最近 ${DAYS_TO_KEEP} 天的备份"
定时备份(Crontab)
# 编辑 crontab
crontab -e
# 每天凌晨 2 点执行备份
0 2 * * * /path/to/backup_script.sh >> /var/log/mongodb_backup.log 2>&1
# 每周日凌晨 3 点执行完整备份
0 3 * * 0 /path/to/backup_script.sh >> /var/log/mongodb_backup.log 2>&1
备份恢复最佳实践
1. 备份前检查
# 检查磁盘空间
df -h /backup
# 检查 MongoDB 状态
mongosh --eval "rs.status()"
# 检查数据大小
mongosh --eval "db.stats()"
2. 验证备份有效性
# 定期测试恢复流程
# 1. 恢复到测试环境
mongorestore --host test-mongo --port 27017 --drop /backup/20240115/myapp
# 2. 验证数据完整性
mongosh test-mongo --eval "db.users.countDocuments()"
# 3. 检查索引
mongosh test-mongo --eval "db.users.getIndexes()"
3. 监控备份状态
# 检查备份文件大小
du -sh /backup/mongodb/*
# 检查备份文件完整性
ls -la /backup/mongodb/$(date +%Y%m%d)/*
# 监控备份日志
tail -f /var/log/mongodb_backup.log
4. 制定恢复计划
| 场景 | 恢复方法 | 预计时间 |
|---|---|---|
| 误删单条记录 | 从备份恢复特定文档 | 分钟级 |
| 误删集合 | mongorestore 恢复集合 | 分钟到小时 |
| 数据库损坏 | 完整恢复 | 小时级 |
| 灾难恢复 | 异地备份恢复 | 数小时 |
常见问题
1. 备份过程中数据库会被锁住吗?
mongodump:不会锁住数据库,但会增加系统负载。建议在低峰期执行。
文件系统快照:需要短暂锁定(fsyncLock),通常只需几秒。
2. 如何备份大型数据库?
# 方法1:并行备份多个集合
mongodump --host localhost --db myapp --collection users --out /backup &
mongodump --host localhost --db myapp --collection orders --out /backup &
wait
# 方法2:使用文件系统快照
# 见上文文件系统快照部分
# 方法3:从副本集从节点备份
mongodump --host secondary1:27017 --db myapp --out /backup
3. 如何实现时间点恢复?
# 备份时记录 oplog
mongodump --host localhost --oplog --out /backup/$(date +%Y%m%d)
# 恢复时重放 oplog
mongorestore --host localhost --oplogReplay /backup/20240115
小结
本章我们学习了:
- 备份策略:3-2-1 原则和备份规划
- mongodump/mongorestore:逻辑备份工具的使用
- 文件系统快照:物理备份方式
- mongoexport/mongoimport:JSON/CSV 格式导出导入
- 延迟节点:热备份方案
- Atlas 云备份:云端自动备份
- 备份脚本:自动化备份实践
- 最佳实践:验证、监控、恢复计划
备份是数据安全的最后一道防线,请务必重视并定期验证备份的有效性。