引言:为什么MongoDB备份至关重要
在当今数据驱动的世界中,MongoDB作为最受欢迎的NoSQL数据库之一,承载着众多企业的核心业务数据。然而,许多开发者和DBA往往低估了数据库备份的重要性,直到发生数据丢失事件时才追悔莫及。本文将深入探讨MongoDB备份的完整策略,从基础概念到高级实践,帮助您构建坚不可摧的数据保护体系。
数据丢失的风险无处不在:硬件故障、人为误操作、恶意攻击、软件Bug,甚至是自然灾害。根据行业统计,超过60%的企业在遭遇重大数据丢失后会在一年内倒闭。因此,制定完善的备份策略不是可选项,而是必选项。
MongoDB备份的核心概念
1. MongoDB架构对备份的影响
MongoDB的灵活架构为备份带来了独特的挑战和机遇:
- 单节点模式:最简单的备份场景
- 副本集(Replica Set):高可用架构,提供天然的备份优势
- 分片集群(Sharded Cluster):最复杂的备份场景,需要协调多个组件
理解您的部署架构是制定备份策略的第一步。
2. 数据一致性要求
MongoDB支持多种写入关注点(Write Concern),这直接影响备份的一致性保证:
w:1:默认设置,仅保证主节点写入w:majority:保证多数节点写入,更适合备份场景w: "majority", j: true:保证写入到日志,提供更强的一致性
MongoDB备份方法详解
方法一:使用mongodump进行逻辑备份
mongodump是MongoDB官方提供的逻辑备份工具,它生成BSON格式的备份文件,适合跨版本迁移和选择性恢复。
基本使用示例
# 基本备份命令(备份所有数据库)
mongodump --host localhost --port 27017 --out /backup/mongodb/$(date +%Y%m%d)
# 指定用户名密码备份
mongodump --host localhost --port 27017 \
--username admin --password "your_password" \
--authenticationDatabase admin \
--out /backup/mongodb/$(date +%Y%m%d)
# 仅备份特定数据库
mongodump --db myapp --collection users \
--host localhost --port 27017 \
--out /backup/mongodb/$(date +%Y%m%d)
# 使用gzip压缩备份
mongodump --host localhost --port 27017 \
--gzip --out /backup/mongodb/$(date +%Y%m%d)
# 增量备份(结合oplog)
mongodump --host localhost --port 27017 \
--oplog --out /backup/mongodb/$(date +%Y%m%d)
恢复命令示例
# 基本恢复
mongorestore --host localhost --port 27017 \
--dir /backup/mongodb/20240101
# 恢复时重命名数据库
mongorestore --host localhost --port 27017 \
--nsFrom 'myapp.*' --nsTo 'myapp_restore.*' \
--dir /backup/mongodb/20240101/myapp
# 恢复时忽略索引(加快恢复速度)
mongorestore --host localhost --port 27017 \
--noIndexRestore \
--dir /backup/mongodb/20240101
# 恢复特定集合
mongorestore --host localhost --port 27017 \
--collection users --db myapp \
--dir /backup/mongodb/20240101/myapp/users.bson
高级选项和性能优化
# 并行备份(使用多个连接)
mongodump --host localhost --port 27017 \
--numParallelCollections=4 \
--out /backup/mongodb/$(date +%Y%m%d)
# 备份时排除系统数据库
mongodump --host localhost --port 27017 \
--excludeDatabases admin,local \
--out /backup/mongodb/$(date +%Y%m%d)
# 使用query过滤备份数据(仅备份符合条件的文档)
mongodump --host localhost --port 27017 \
--db myapp --collection logs \
--query '{"timestamp": {"$gte": {"$date": "2024-01-01T00:00:00Z"}}}' \
--out /backup/mongodb/$(date +%Y%m%d)
方法二:使用文件系统快照(物理备份)
文件系统快照提供几乎瞬时的备份,对大型数据库特别有效。这种方法利用存储层的快照功能,如LVM、ZFS或云提供商的快照服务。
LVM快照示例(Linux)
#!/bin/bash
# MongoDB LVM快照备份脚本
MONGO_DATA="/var/lib/mongodb"
SNAP_NAME="mongodb-snap-$(date +%Y%m%d-%H%M%S)"
SNAP_SIZE="10G"
# 1. 确保MongoDB使用journaling(必须)
mongo --eval "db.adminCommand({getParameter:1, journalCommitInterval:1})"
# 2. 刷新并锁定数据库(短暂)
echo "正在锁定数据库..."
mongo --eval "db.fsyncLock()"
# 3. 创建LVM快照
echo "创建LVM快照..."
lvcreate --size $SNAP_SIZE --snapshot --name $SNAP_NAME $MONGO_DATA
# 4. 解锁数据库
echo "解锁数据库..."
mongo --eval "db.fsyncUnlock()"
# 5. 挂载快照并复制数据
MOUNT_POINT="/mnt/mongodb-snap"
mkdir -p $MOUNT_POINT
mount /dev/vg0/$SNAP_NAME $MOUNT_POINT
# 6. 创建备份归档
BACKUP_DIR="/backup/mongodb/snapshots"
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/$SNAP_NAME.tar.gz -C $MOUNT_POINT .
# 7. 清理
umount $MOUNT_POINT
lvremove -f /dev/vg0/$SNAP_NAME
echo "备份完成: $BACKUP_DIR/$SNAP_NAME.tar.gz"
ZFS快照示例
#!/bin/bash
# ZFS快照备份脚本
ZFS_POOL="tank/mongodb/data"
BACKUP_DIR="/backup/mongodb/zfs"
# 1. 创建ZFS快照
SNAP_NAME="mongodb-snap-$(date +%Y%m%d-%H%M%S)"
zfs snapshot $ZFS_POOL@$SNAP_NAME
# 2. 发送快照到备份服务器
zfs send $ZFS_POOL@$SNAP_NAME | ssh backup-server "zfs receive tank/mongodb/backup/$SNAP_NAME"
# 3. 清理旧快照(保留最近7天)
zfs list -t snapshot -o name -s creation | grep mongodb-snap | head -n -7 | xargs -I {} zfs destroy {}
echo "ZFS快照备份完成: $SNAP_NAME"
方法三:使用MongoDB Atlas备份(云托管方案)
MongoDB Atlas提供企业级备份解决方案,包括:
- 连续备份:每小时增量备份
- 时间点恢复(PITR):精确到秒级恢复
- 全球分布:跨区域备份存储
# 使用Atlas CLI创建备份(示例)
atlas backups snapshots create \
--clusterName myCluster \
--retention 7 \
--description "Daily backup"
# 恢复到指定时间点
atlas backups snapshots restore \
--clusterName myCluster \
--targetClusterName myCluster \
--targetSnapshotId snapshot-123 \
--deliveryType pointInTime \
--timestamp "2024-01-15T14:30:00Z"
备份策略设计
1. 3-2-1备份法则
3-2-1法则是备份的黄金标准:
- 3:至少3份数据副本(原始数据 + 2个备份)
- 2:至少2种不同的存储介质
- 1:至少1份异地备份
实际部署示例
# backup-strategy.yaml
backup_strategy:
name: "Production MongoDB Backup"
description: "遵循3-2-1法则的完整备份策略"
replicas:
- type: "primary"
location: "生产数据库"
medium: "SSD存储"
- type: "local_backup"
location: "本地备份服务器"
medium: "HDD存储"
retention: "7天"
- type: "remote_backup"
location: "异地数据中心/S3"
medium: "云存储"
retention: "30天"
schedule:
full_backup:
frequency: "daily"
time: "02:00"
method: "mongodump"
incremental_backup:
frequency: "hourly"
method: "oplog"
snapshot_backup:
frequency: "weekly"
day: "Sunday"
method: "filesystem_snapshot"
2. 备份频率与保留策略
根据数据变化频率和业务需求制定策略:
| 数据类型 | 备份频率 | 保留期限 | 恢复时间目标(RTO) | 恢复点目标(RPO) |
|---|---|---|---|---|
| 核心交易数据 | 每小时增量 + 每日全量 | 90天 | < 1小时 | < 1小时 |
| 用户行为日志 | 每日全量 | 30天 | < 4小时 | < 24小时 |
| 临时数据 | 每周全量 | 7天 | < 24小时 | < 7天 |
| 归档数据 | 每月全量 | 永久 | < 24小时 | < 30天 |
3. 备份验证与测试
备份不验证等于没有备份。必须定期验证备份的完整性和可恢复性。
自动化验证脚本
#!/usr/bin/env python3
# backup_verification.py
import subprocess
import json
import sys
from datetime import datetime, timedelta
def verify_backup(backup_path):
"""验证备份文件的完整性"""
try:
# 检查备份文件是否存在
result = subprocess.run(
['ls', '-lh', backup_path],
capture_output=True,
text=True
)
if result.returncode != 0:
print(f"❌ 备份文件不存在: {backup_path}")
return False
# 验证BSON文件完整性
verify_cmd = [
'mongodump',
'--verify',
'--dir', backup_path
]
result = subprocess.run(verify_cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"✅ 备份验证通过: {backup_path}")
return True
else:
print(f"❌ 备份验证失败: {result.stderr}")
return False
except Exception as e:
print(f"❌ 验证过程异常: {str(e)}")
return False
def test_restore(backup_path, test_db_name="test_restore"):
"""在隔离环境中测试恢复"""
try:
# 创建临时MongoDB实例(使用Docker)
container_name = f"mongo-test-{datetime.now().strftime('%Y%m%d%H%M%S')}"
# 启动临时实例
subprocess.run([
'docker', 'run', '-d',
'--name', container_name,
'-p', '27018:27017',
'mongo:latest'
], check=True)
# 等待实例启动
subprocess.run(['sleep', '10'])
# 恢复备份
restore_cmd = [
'mongorestore',
'--host', 'localhost',
'--port', '27018',
'--dir', backup_path
]
result = subprocess.run(restore_cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"✅ 恢复测试通过")
success = True
else:
print(f"❌ 恢复测试失败: {result.stderr}")
success = False
# 清理临时实例
subprocess.run(['docker', 'stop', container_name], check=True)
subprocess.run(['docker', 'rm', container_name], check=True)
return success
except Exception as e:
print(f"❌ 恢复测试异常: {str(e)}")
# 确保清理
try:
subprocess.run(['docker', 'rm', '-f', container_name], check=True)
except:
pass
return False
def main():
backup_path = sys.argv[1] if len(sys.argv) > 1 else "/backup/mongodb/latest"
print(f"开始验证备份: {backup_path}")
print("=" * 50)
# 步骤1: 验证备份文件
if not verify_backup(backup_path):
sys.exit(1)
# 步骤2: 测试恢复(可选,生产环境慎用)
if len(sys.argv) > 2 and sys.argv[2] == "--test-restore":
print("\n开始恢复测试...")
if not test_restore(backup_path):
sys.exit(1)
print("\n✅ 所有验证通过!")
sys.exit(0)
if __name__ == "__main__":
main()
4. 自动化备份脚本
完整的每日备份脚本
#!/bin/bash
# daily_mongodb_backup.sh
set -euo pipefail
# 配置
BACKUP_ROOT="/backup/mongodb"
DATE=$(date +%Y%m%d)
BACKUP_DIR="$BACKUP_ROOT/$DATE"
LOG_FILE="$BACKUP_ROOT/backup.log"
RETENTION_DAYS=7
NOTIFY_EMAIL="dba@company.com"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 错误处理
error_exit() {
log "ERROR: $1"
echo "备份失败,请检查日志: $LOG_FILE" | mail -s "MongoDB备份失败" $NOTIFY_EMAIL
exit 1
}
# 检查MongoDB状态
log "检查MongoDB状态..."
if ! mongo --quiet --eval "db.adminCommand('ping')" > /dev/null 2>&1; then
error_exit "MongoDB无法连接"
fi
# 创建备份目录
mkdir -p $BACKUP_DIR
# 执行备份
log "开始备份MongoDB..."
if mongodump \
--host localhost \
--port 27017 \
--username backup_user \
--password "$MONGO_BACKUP_PASSWORD" \
--authenticationDatabase admin \
--gzip \
--oplog \
--numParallelCollections=4 \
--out $BACKUP_DIR 2>> $LOG_FILE; then
log "备份成功完成"
else
error_exit "备份执行失败"
fi
# 计算备份大小
BACKUP_SIZE=$(du -sh $BACKUP_DIR | cut -f1)
log "备份大小: $BACKUP_SIZE"
# 验证备份
log "验证备份完整性..."
python3 /usr/local/bin/backup_verification.py $BACKUP_DIR
if [ $? -ne 0 ]; then
error_exit "备份验证失败"
fi
# 上传到远程存储(S3示例)
log "上传备份到S3..."
if aws s3 cp $BACKUP_DIR s3://mongodb-backups/$DATE/ --recursive; then
log "S3上传成功"
else
log "WARNING: S3上传失败,继续本地保留"
fi
# 清理旧备份
log "清理旧备份(保留$RETENTION_DAYS天)..."
find $BACKUP_ROOT -type d -mtime +$RETENTION_DAYS -exec rm -rf {} + 2>> $LOG_FILE
aws s3 ls s3://mongodb-backups/ | awk '{print $2}' | while read dir; do
dir_date=$(echo $dir | tr -d '/')
if [[ $dir_date < $(date -d "$RETENTION_DAYS days ago" +%Y%m%d) ]]; then
aws s3 rm s3://mongodb-backups/$dir --recursive
fi
done
log "清理完成"
# 发送成功通知
echo "MongoDB备份成功完成
日期: $DATE
大小: $BACKUP_SIZE
位置: $BACKUP_DIR
验证: 通过" | mail -s "MongoDB备份成功" $NOTIFY_EMAIL
log "备份流程完成"
exit 0
灾难恢复最佳实践
1. 灾难恢复计划(DRP)制定
灾难恢复计划应包括:
- 风险评估:识别可能的灾难场景
- 恢复优先级:确定恢复顺序
- 人员职责:明确每个团队成员的角色
- 联系清单:关键人员联系方式
- 恢复步骤:详细的操作手册
灾难场景应对矩阵
| 灾难场景 | 检测方法 | 响应时间 | 恢复步骤 | 验证方法 |
|---|---|---|---|---|
| 单节点故障 | 监控告警 | 5分钟 | 自动切换到副本集 | 应用测试 |
| 误删除数据 | 审计日志 | 15分钟 | 从备份恢复 | 数据校验 |
| 勒索软件 | 异常检测 | 立即 | 隔离+恢复备份 | 完整性扫描 |
| 数据中心故障 | 服务中断 | 5分钟 | DNS切换到DR站点 | 端到端测试 |
| 区域性故障 | 多地监控 | 10分钟 | 启用异地备份 | 业务验证 |
2. 自动化故障转移与恢复
副本集自动恢复脚本
#!/usr/bin/env python3
# auto_failover.py
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure, OperationFailure
import time
import smtplib
from email.mime.text import MIMEText
class MongoDBFailoverManager:
def __init__(self, replica_set_uri, backup_path):
self.uri = replica_set_uri
self.backup_path = backup_path
self.client = None
def connect(self):
"""连接到副本集"""
try:
self.client = MongoClient(self.uri, serverSelectionTimeoutMS=5000)
self.client.admin.command('ping')
return True
except Exception as e:
print(f"连接失败: {e}")
return False
def check_health(self):
"""检查副本集健康状态"""
try:
status = self.client.admin.command('replSetGetStatus')
# 检查主节点
primary = None
secondaries = []
for member in status['members']:
if member['stateStr'] == 'PRIMARY':
primary = member
elif member['stateStr'] == 'SECONDARY':
secondaries.append(member)
# 检查是否有主节点
if not primary:
print("警告: 没有主节点")
return False
# 检查延迟
if primary['optimeDate'] < datetime.now() - timedelta(minutes=5):
print("警告: 主节点延迟过大")
return False
return True
except Exception as e:
print(f"健康检查失败: {e}")
return False
def initiate_failover(self):
"""手动触发故障转移"""
try:
# 连接到当前主节点并执行stepDown
self.client.admin.command('replSetStepDown', 60)
print("故障转移已触发")
return True
except Exception as e:
print(f"故障转移失败: {e}")
return False
def restore_from_backup(self, target_node):
"""从备份恢复到指定节点"""
import subprocess
try:
# 停止目标节点
subprocess.run(['systemctl', 'stop', 'mongod'], check=True)
# 清空数据目录
subprocess.run(['rm', '-rf', '/var/lib/mongodb/*'], check=True)
# 恢复备份
restore_cmd = [
'mongorestore',
'--host', target_node,
'--port', '27017',
'--dir', self.backup_path,
'--oplogReplay'
]
subprocess.run(restore_cmd, check=True)
# 启动服务
subprocess.run(['systemctl', 'start', 'mongod'], check=True)
print(f"从备份恢复完成: {target_node}")
return True
except Exception as e:
print(f"恢复失败: {e}")
return False
def send_alert(self, message):
"""发送告警邮件"""
msg = MIMEText(message)
msg['Subject'] = 'MongoDB灾难恢复告警'
msg['From'] = 'monitor@company.com'
msg['To'] = 'dba@company.com'
try:
with smtplib.SMTP('smtp.company.com') as server:
server.send_message(msg)
print("告警已发送")
except Exception as e:
print(f"发送告警失败: {e}")
# 使用示例
if __name__ == "__main__":
manager = MongoDBFailoverManager(
replica_set_uri="mongodb://node1:27017,node2:27017,node3:27017/?replicaSet=rs0",
backup_path="/backup/mongodb/latest"
)
if not manager.connect():
manager.send_alert("无法连接到MongoDB副本集")
exit(1)
if not manager.check_health():
manager.send_alert("MongoDB副本集健康检查失败")
# 可以在这里触发自动恢复
# manager.initiate_failover()
# manager.restore_from_backup("node2")
3. 时间点恢复(PITR)实现
时间点恢复是灾难恢复的高级形式,允许恢复到任意时间点。
基于Oplog的时间点恢复
#!/bin/bash
# point_in_time_restore.sh
# 配置
BACKUP_ROOT="/backup/mongodb"
RESTORE_TIME="2024-01-15T14:30:00Z"
TARGET_DB="myapp"
RESTORE_DIR="/tmp/restore_$$"
# 创建恢复目录
mkdir -p $RESTORE_DIR
# 步骤1: 找到最接近的完整备份
find_backup() {
local target_date=$(date -d "$RESTORE_TIME" +%s)
local best_backup=""
local best_diff=999999999
for backup in $BACKUP_ROOT/*; do
if [ -d "$backup" ]; then
backup_date=$(date -d "$(basename $backup)" +%s 2>/dev/null || echo 0)
if [ $backup_date -gt 0 ] && [ $backup_date -le $target_date ]; then
diff=$((target_date - backup_date))
if [ $diff -lt $best_diff ]; then
best_diff=$diff
best_backup=$backup
fi
fi
fi
done
echo $best_backup
}
# 步骤2: 恢复完整备份
BACKUP=$(find_backup)
if [ -z "$BACKUP" ]; then
echo "未找到合适的备份"
exit 1
fi
echo "使用备份: $BACKUP"
mongorestore --host localhost --port 27017 --dir $BACKUP --db $TARGET_DB
# 步骤3: 重放Oplog到指定时间点
OPLOG_FILE="$BACKUP/oplog.bson"
if [ -f "$OPLOG_FILE" ]; then
# 提取Oplog到指定时间点
mongorestore \
--host localhost \
--port 27017 \
--oplogReplay \
--oplogLimit "$RESTORE_TIME" \
--dir $BACKUP
fi
echo "时间点恢复完成: $RESTORE_TIME"
4. 灾难恢复演练
定期演练是确保DR计划有效的关键。
演练脚本示例
#!/bin/bash
# disaster_recovery_drill.sh
set -e
echo "开始灾难恢复演练 $(date)"
# 模拟灾难:停止主节点
echo "模拟主节点故障..."
systemctl stop mongod
# 等待自动故障转移
echo "等待故障转移..."
sleep 30
# 验证新主节点
PRIMARY=$(mongo --quiet --eval "rs.isMaster().primary" 2>/dev/null || echo "none")
if [ "$PRIMARY" != "none" ]; then
echo "✅ 故障转移成功: $PRIMARY"
else
echo "❌ 故障转移失败"
exit 1
fi
# 模拟数据丢失
echo "模拟数据丢失..."
mongo --eval "db.test_collection.insert({drill: true, timestamp: new Date()})" > /dev/null
mongo --eval "db.test_collection.drop()" > /dev/null
# 从备份恢复
echo "从备份恢复..."
/usr/local/bin/restore_from_backup.sh /backup/mongodb/latest
# 验证恢复
COUNT=$(mongo --quiet --eval "db.test_collection.count()" 2>/dev/null || echo "0")
if [ "$COUNT" -gt 0 ]; then
echo "✅ 数据恢复成功"
else
echo "❌ 数据恢复失败"
exit 1
fi
# 恢复原始状态
echo "恢复原始状态..."
systemctl start mongod
echo "灾难恢复演练完成 $(date)"
监控与告警
1. 备份监控指标
关键监控指标:
- 备份成功率
- 备份持续时间
- 备份文件大小
- 恢复测试成功率
- 存储空间使用率
Prometheus监控脚本
#!/usr/bin/env python3
# backup_metrics_exporter.py
from prometheus_client import start_http_server, Gauge, Counter
import subprocess
import json
import time
import os
# 定义指标
backup_success = Counter('mongodb_backup_success_total', 'Total successful backups')
backup_failure = Counter('mongodb_backup_failure_total', 'Total failed backups')
backup_duration = Gauge('mongodb_backup_duration_seconds', 'Last backup duration')
backup_size = Gauge('mongodb_backup_size_bytes', 'Last backup size')
restore_test_success = Counter('mongodb_restore_test_success_total', 'Total successful restore tests')
def collect_metrics():
"""收集备份指标"""
backup_log = "/backup/mongodb/backup.log"
if not os.path.exists(backup_log):
return
# 解析日志获取指标
with open(backup_log, 'r') as f:
lines = f.readlines()
# 分析最近的备份记录
for line in reversed(lines):
if "备份成功完成" in line:
backup_success.inc()
# 提取大小和时间信息
# 这里简化处理,实际应解析具体数值
break
elif "ERROR" in line:
backup_failure.inc()
break
def run_restore_test():
"""执行恢复测试并记录指标"""
try:
result = subprocess.run(
['/usr/local/bin/backup_verification.py', '/backup/mongodb/latest'],
capture_output=True,
timeout=3600
)
if result.returncode == 0:
restore_test_success.inc()
return True
else:
return False
except:
return False
if __name__ == '__main__':
# 启动HTTP服务器
start_http_server(9100)
while True:
collect_metrics()
# 每小时执行一次恢复测试
current_hour = time.localtime().tm_hour
if current_hour % 1 == 0: # 每小时
run_restore_test()
time.sleep(300) # 每5分钟更新一次
2. 告警规则示例(Prometheus)
# alert_rules.yml
groups:
- name: mongodb_backup_alerts
rules:
- alert: MongoDBBackupFailed
expr: increase(mongodb_backup_failure_total[1d]) > 0
for: 5m
labels:
severity: critical
annotations:
summary: "MongoDB备份失败"
description: "过去24小时内备份失败次数: {{ $value }}"
- alert: MongoDBBackupTooOld
expr: time() - mongodb_backup_last_success_timestamp > 86400
for: 10m
labels:
severity: warning
annotations:
summary: "MongoDB备份过时"
description: "最后一次成功备份在{{ $value | humanizeDuration }}前"
- alert: MongoDBRestoreTestFailed
expr: increase(mongodb_restore_test_success_total[168h]) == 0
for: 1h
labels:
severity: warning
annotations:
summary: "MongoDB恢复测试未通过"
description: "过去7天内没有成功的恢复测试"
- alert: MongoDBBackupSizeAnomaly
expr: abs(mongodb_backup_size_bytes - avg_over_time(mongodb_backup_size_bytes[7d])) / stddev_over_time(mongodb_backup_size_bytes[7d]) > 3
for: 10m
labels:
severity: warning
annotations:
summary: "MongoDB备份大小异常"
description: "备份大小偏离正常值超过3个标准差"
高级主题:分片集群备份
1. 分片集群备份挑战
分片集群备份需要协调多个组件:
- Config Servers:存储元数据
- Shards:实际数据分片
- Mongos:路由节点
2. 分片集群备份策略
方法一:Balancer停止法
#!/bin/bash
# sharded_cluster_backup.sh
# 1. 停止均衡器(避免分片迁移)
echo "停止均衡器..."
mongo --host mongos --port 27017 --eval "sh.stopBalancer()"
# 等待正在进行的迁移完成
while true; do
in_progress=$(mongo --host mongos --port 27017 --quiet --eval "db.getSiblingDB('config').transactions.find({state: 'inProgress'}).count()")
if [ "$in_progress" -eq 0 ]; then
break
fi
echo "等待迁移完成..."
sleep 10
done
# 2. 备份Config Servers(必须一致)
echo "备份Config Servers..."
mongodump --host config1 --port 27019 \
--db config \
--out /backup/sharded/config_$(date +%Y%m%d)
# 3. 并行备份所有Shards
echo "备份Shards..."
for shard in shard1 shard2 shard3; do
mongodump --host $shard --port 27018 \
--out /backup/sharded/${shard}_$(date +%Y%m%d) &
done
wait
# 4. 重新启用均衡器
echo "启用均衡器..."
mongo --host mongos --port 27017 --eval "sh.startBalancer()"
echo "分片集群备份完成"
方法二:使用MongoDB Atlas(推荐)
MongoDB Atlas自动处理分片集群备份的复杂性。
3. 分片集群恢复
#!/bin/bash
# sharded_cluster_restore.sh
# 1. 停止所有Mongos
systemctl stop mongos
# 2. 恢复Config Servers
mongorestore --host config1 --port 27019 \
--db config \
--dir /backup/sharded/config_20240101
# 3. 恢复每个Shard
for shard in shard1 shard2 shard3; do
mongorestore --host $shard --port 27018 \
--dir /backup/sharded/${shard}_20240101 &
done
wait
# 4. 启动Mongos
systemctl start mongos
# 5. 验证集群状态
mongo --host mongos --port 27017 --eval "sh.status()"
备份存储与安全
1. 加密备份
# 使用GPG加密备份
mongodump --host localhost --port 27017 --out - | \
gpg --cipher-algo AES256 --compress-algo 1 --symmetric --output /backup/mongodb/encrypted_$(date +%Y%m%d).gpg
# 解密恢复
gpg --decrypt /backup/mongodb/encrypted_20240101.gpg | \
mongorestore --host localhost --port 27017 --dir -
2. 备份完整性验证
# 生成校验和
find /backup/mongodb/20240101 -type f -exec sha256sum {} \; > /backup/mongodb/20240101.sha256
# 验证校验和
sha256sum -c /backup/mongodb/20240101.sha256
总结与检查清单
备份策略检查清单
- [ ] 是否遵循3-2-1备份法则?
- [ ] 备份频率是否满足RPO要求?
- [ ] 是否有定期的恢复测试?
- [ ] 备份是否加密存储?
- [ ] 是否有监控和告警?
- [ ] 是否有详细的灾难恢复文档?
- [ ] 团队成员是否熟悉恢复流程?
- [ ] 是否定期进行灾难恢复演练?
- [ ] 备份存储空间是否充足?
- [ ] 是否有异地备份?
关键要点回顾
- 备份不是目的,恢复才是:定期测试恢复流程至关重要
- 自动化一切:手动操作容易出错,尽量自动化
- 监控驱动:没有监控的备份等于没有备份
- 分层策略:根据数据重要性制定不同策略
- 持续改进:定期审查和优化备份策略
通过实施本文介绍的策略和工具,您可以构建一个强大、可靠的MongoDB备份和灾难恢复体系,最大程度地降低数据丢失风险,确保业务连续性。记住,数据是您最宝贵的资产,保护它是每个DBA和开发者的责任。
