引言:为什么MongoDB备份至关重要

在现代应用架构中,MongoDB作为领先的NoSQL数据库,承载着大量关键业务数据。然而,许多开发者和DBA往往低估了备份的重要性,直到发生数据丢失或损坏时才追悔莫及。一个完善的备份策略不仅仅是数据的简单复制,更是业务连续性的基石。

想象一下这样的场景:凌晨3点,你的MongoDB主节点突然崩溃,而你上一次备份是在一周前,期间产生了大量重要交易数据。或者更糟糕的是,你发现备份文件存在但无法恢复,因为备份过程中存在未被察觉的配置错误。这些情况并非危言耸听,而是真实发生过的生产事故。

本文将从基础概念出发,深入探讨MongoDB的各种备份策略,涵盖从单机部署到高可用集群的完整方案,并揭示常见的误区和最佳实践。无论你是刚接触MongoDB的新手,还是经验丰富的运维专家,都能从中获得有价值的见解。

第一部分:MongoDB备份基础概念

1.1 MongoDB数据存储原理简述

要制定有效的备份策略,首先需要理解MongoDB是如何存储数据的。MongoDB使用B-Tree索引结构将数据存储在数据文件中(默认路径为/data/db),每个数据库对应一组文件,其中.ns文件存储元数据,.0.1等文件存储实际数据。

MongoDB的写操作首先写入内存(WiredTiger引擎的缓存),然后由后台线程定期刷入磁盘。这意味着即使服务器突然断电,也可能丢失最近几秒的写入数据。理解这一点对确定备份窗口和恢复点目标(RPO)至关重要。

1.2 备份的核心目标

任何备份策略都应围绕三个核心目标设计:

  1. 数据完整性:确保备份数据完整且一致
  2. 恢复速度:在需要时能快速恢复服务
  3. 存储效率:平衡存储成本与备份频率

1.3 MongoDB原生备份工具

MongoDB提供了两种主要的原生备份工具:

mongodump

mongodump是MongoDB提供的逻辑备份工具,它通过连接到运行的mongod实例,读取数据并生成BSON文件。

# 基本使用示例
mongodump --host localhost --port 27017 --out /backup/mongodb/$(date +%F)

# 带认证的备份
mongodump --host db1.example.com --username backupUser --password "secret" --authenticationDatabase admin --out /backup/mongodb/

# 备份单个数据库
mongodump --db myapp --collection users --out /backup/mongodb/

mongodump的优点是:

  • 跨平台兼容
  • 可以备份单个集合或数据库
  • 支持查询过滤
  • 无需停止服务

缺点是:

  • 大数据量时速度较慢
  • 备份过程中可能产生额外负载

mongorestore

mongorestore用于从mongodump生成的BSON文件中恢复数据:

# 基本恢复
mongorestore --host localhost --port 27017 /backup/mongodb/2023-10-15/

# 恢复时指定不同数据库名
mongorestore --db newdb --nsFrom 'myapp.*' --nsTo 'newapp.*' /backup/mongodb/

# 带认证的恢复
mongorestore --username restoreUser --password "secret" --authenticationDatabase admin /backup/mongodb/

文件系统备份(物理备份)

除了逻辑备份,还可以直接备份MongoDB的数据文件:

# 1. 锁定数据库(防止写入)
mongod --dbpath /data/db --repair

# 2. 复制数据文件
rsync -av /data/db /backup/mongodb/filebackup/

# 3. 解锁
mongod --dbpath /data/db --shutdown

文件系统备份的优点是速度快,特别适合大数据量场景;缺点是需要停机或加锁,且备份文件与平台相关。

第二部分:基础备份策略

2.1 单节点MongoDB备份方案

对于开发环境或小型应用,可以采用简单的定期备份策略:

#!/bin/bash
# 单节点MongoDB备份脚本示例

BACKUP_DIR="/backup/mongodb"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7

# 创建备份目录
mkdir -p $BACKUP_DIR/$DATE

# 执行备份
mongodump --host localhost --port 27017 --out $BACKUP_DIR/$DATE

# 压缩备份(可选)
tar -czf $BACKUP_DIR/mongodb_$DATE.tar.gz -C $BACKUP_DIR $DATE
rm -rf $BACKUP_DIR/$DATE

# 清理旧备份
find $BACKUP_DIR -name "mongodb_*.tar.gz" -mtime +$RETENTION_DAYS -delete

# 记录日志
echo "[$(date)] Backup completed: mongodb_$DATE.tar.gz" >> /var/log/mongodb_backup.log

将此脚本添加到crontab中实现自动化:

# 每天凌晨2点执行备份
0 2 * * * /path/to/backup_script.sh

2.2 增量备份与全量备份

MongoDB本身不支持真正的增量备份,但可以通过以下方式模拟:

Oplog重放

MongoDB副本集的oplog记录了所有数据变更操作。通过定期备份全量数据+持续备份oplog,可以实现类似增量恢复的效果:

# 1. 全量备份
mongodump --oplog --out /backup/full_$(date +%F)

# 2. 后续备份oplog(每小时)
mongodump -d local -c oplog.rs --query '{ts:{$gte:Timestamp(开始时间戳)}}' --out /backup/oplog/

文件系统增量备份

使用支持增量备份的文件系统工具(如rsync、btrfs等):

# 使用rsync进行增量备份
rsync -av --delete /data/db/ /backup/mongodb/incremental/

2.3 备份验证与测试

备份不经过验证等于没有备份。定期测试恢复流程至关重要:

#!/bin/bash
# 备份验证脚本

BACKUP_FILE="/backup/mongodb/mongodb_20231015.tar.gz"
TEST_DB="test_restore_$(date +%s)"

# 解压备份
tar -xzf $BACKUP_FILE -C /tmp

# 恢复到测试数据库
mongorestore --db $TEST_DB /tmp/dump/

# 验证数据完整性
mongo $TEST_DB --eval "db.stats()" | grep -q "ok.*1" && echo "验证成功" || echo "验证失败"

# 清理测试数据
mongo --eval "db.getSiblingDB('$TEST_DB').dropDatabase()"
rm -rf /tmp/dump

第三部分:副本集备份策略

3.1 副本集备份最佳实践

在副本集环境中,最佳实践是从Secondary节点进行备份,避免影响Primary节点的性能:

# 从Secondary节点备份
mongodump --host secondary_host --port 27017 --out /backup/mongodb/

# 或者在连接字符串中指定读偏好
mongodump --uri "mongodb://secondary_host:27017/?readPreference=secondary" --out /backup/mongodb/

3.2 备份窗口优化

对于大型副本集,可以采用分片备份策略:

# 按分片并行备份
for shard in shard1 shard2 shard3; do
    mongodump --host $shard --out /backup/mongodb/$shard &
done
wait

3.3 副本集备份脚本示例

#!/bin/bash
# 副本集备份脚本

REPLSET="rs0"
SECONDARIES=("rs0/secondary1:27017" "rs0/secondary2:27017")
BACKUP_DIR="/backup/mongodb/replset_$(date +%Y%m%d)"
RETENTION_DAYS=30

# 选择负载最低的secondary
PRIMARY=$(mongo --eval "db.isMaster().primary" --quiet)
for node in "${SECONDARIES[@]}"; do
    LOAD=$(mongo --host $node --eval "db.serverStatus().globalLock.activeClients" --quiet)
    if [ -z "$BEST_NODE" ] || [ "$LOAD" -lt "$BEST_LOAD" ]; then
        BEST_NODE=$node
        BEST_LOAD=$LOAD
    fi
done

# 执行备份
mongodump --host $BEST_NODE --out $BACKUP_DIR --oplog

# 创建恢复元数据
cat > $BACKUP_DIR/recovery_info.json <<EOF
{
    "timestamp": $(date +%s),
    "source_node": "$BEST_NODE",
    "replset": "$REPLSET",
    "oplog": true
}
EOF

# 清理旧备份
find /backup/mongodb -name "replset_*" -mtime +$RETENTION_DAYS -exec rm -rf {} \;

第四部分:分片集群备份

4.1 分片集群架构理解

MongoDB分片集群包含以下组件:

  • Config Servers:存储元数据
  • Shards:实际数据分片
  • Mongos:路由请求

备份分片集群需要协调所有组件,确保一致性。

4.2 分片集群备份策略

方法1:停机备份(简单但影响业务)

# 1. 停止所有mongos
mongos --shutdown

# 2. 备份所有分片和config server
for node in config1 shard1 shard2 shard3; do
    mongodump --host $node --out /backup/cluster/$node &
done
wait

# 3. 启动服务
mongos --configdb config1:27019 --bind_ip_all

方法2:一致性快照备份(推荐)

#!/bin/bash
# 分片集群一致性备份

# 1. 在所有节点启用一致性快照
mongo --eval "db.adminCommand({setParameter:1, enableShardSnapshot: true})"

# 2. 获取所有分片和config server信息
SHARDS=$(mongo --eval "db.adminCommand({listShards:1}).shards" --quiet)
CONFIGS=$(mongo --eval "db.adminCommand({getCmdLineOpts:1}).parsed.sharding.configDB" --quiet)

# 3. 并行备份所有节点
for shard in $SHARDS; do
    mongodump --host $shard --out /backup/cluster/shards/$shard &
done

for config in $CONFIGS; do
    mongodump --host $config --out /backup/cluster/configs/$config &
done

wait

# 4. 记录快照时间戳
mongo --eval "db.adminCommand({getCmdLineOpts:1}).parsed.sharding.clusterId" > /backup/cluster/cluster_id.txt

4.3 分片集群恢复注意事项

恢复分片集群时需要特别注意:

  1. 必须先恢复config server
  2. 各分片的数据必须与config server的元数据匹配
  3. 恢复后需要重新平衡数据

第五部分:高可用备份方案

5.1 自动化备份系统架构

一个高可用的备份系统应该包含:

  • 多个备份存储位置(本地+云端)
  • 备份状态监控和告警
  • 自动化测试恢复流程
# Python备份管理器示例
import subprocess
import boto3
import json
from datetime import datetime, timedelta

class MongoDBBackupManager:
    def __init__(self, config):
        self.config = config
        self.s3 = boto3.client('s3')
        
    def create_backup(self):
        """创建备份并上传到S3"""
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_name = f"mongodb_backup_{timestamp}"
        
        # 执行备份
        cmd = [
            'mongodump',
            '--host', self.config['host'],
            '--port', str(self.config['port']),
            '--out', f"/tmp/{backup_name}"
        ]
        
        if 'username' in self.config:
            cmd.extend(['--username', self.config['username']])
            cmd.extend(['--password', self.config['password']])
            cmd.extend(['--authenticationDatabase', 'admin'])
            
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode != 0:
            raise Exception(f"Backup failed: {result.stderr}")
            
        # 压缩
        tar_name = f"{backup_name}.tar.gz"
        subprocess.run(['tar', '-czf', f"/tmp/{tar_name}", "-C", "/tmp", backup_name])
        
        # 上传到S3
        self.s3.upload_file(f"/tmp/{tar_name}", self.config['s3_bucket'], tar_name)
        
        # 清理临时文件
        subprocess.run(['rm', '-rf', f"/tmp/{backup_name}", f"/tmp/{tar_name}"])
        
        return tar_name
        
    def verify_backup(self, backup_name):
        """验证备份完整性"""
        # 下载备份
        local_path = f"/tmp/{backup_name}"
        self.s3.download_file(self.config['s3_bucket'], backup_name, local_path)
        
        # 解压并验证
        test_dir = f"/tmp/test_{backup_name.replace('.tar.gz', '')}"
        subprocess.run(['mkdir', '-p', test_dir])
        subprocess.run(['tar', '-xzf', local_path, '-C', test_dir])
        
        # 检查BSON文件
        verify_cmd = ['mongorestore', '--dryRun', f"{test_dir}/dump/"]
        result = subprocess.run(verify_cmd, capture_output=True, text=True)
        
        # 清理
        subprocess.run(['rm', '-rf', local_path, test_dir])
        
        return result.returncode == 0
        
    def cleanup_old_backups(self, days=30):
        """清理旧备份"""
        cutoff_date = datetime.now() - timedelta(days=days)
        
        # 列出S3中的所有备份
        response = self.s3.list_objects_v2(Bucket=self.config['s3_bucket'])
        
        for obj in response.get('Contents', []):
            # 解析对象名称中的日期
            try:
                backup_date_str = obj['Key'].split('_')[2].split('.')[0]
                backup_date = datetime.strptime(backup_date_str, '%Y%m%d')
                
                if backup_date < cutoff_date:
                    self.s3.delete_object(Bucket=self.config['s3_bucket'], Key=obj['Key'])
                    print(f"Deleted old backup: {obj['Key']}")
            except:
                continue

# 使用示例
config = {
    'host': 'localhost',
    'port': 27017,
    'username': 'backupUser',
    'password': 'secret',
    's3_bucket': 'my-mongodb-backups'
}

manager = MongoDBBackupManager(config)
backup_name = manager.create_backup()
if manager.verify_backup(backup_name):
    print(f"Backup {backup_name} created and verified successfully")
else:
    print(f"Backup {backup_name} verification failed!")
    
manager.cleanup_old_backups(days=7)

5.2 云原生备份方案

AWS DocumentDB备份

# AWS DocumentDB自动备份
aws docdb create-db-cluster-snapshot \
    --db-cluster-identifier my-docdb-cluster \
    --db-cluster-snapshot-identifier docdb-snapshot-$(date +%Y%m%d)

# 导出到S3
aws docdb export-to-s3 \
    --db-cluster-identifier my-docdb-cluster \
    --s3-bucket-name my-backup-bucket \
    --s3-prefix backups/

MongoDB Atlas备份

MongoDB Atlas提供托管备份服务:

# 通过Atlas API创建快照
curl -X POST \
  "https://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/clusters/{clusterName}/backup/snapshots" \
  -H "Content-Type: application/json" \
  -d '{"snapshotType":"scheduled","frequencyType":"daily"}'

5.3 备份监控与告警

#!/bin/bash
# 备份监控脚本

BACKUP_DIR="/backup/mongodb"
LOG_FILE="/var/log/mongodb_backup_monitor.log"
ALERT_EMAIL="admin@example.com"

# 检查最近备份时间
LATEST_BACKUP=$(find $BACKUP_DIR -name "*.tar.gz" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
if [ -z "$LATEST_BACKUP" ]; then
    echo "[$(date)] CRITICAL: No backups found!" | mail -s "MongoDB Backup Alert" $ALERT_EMAIL
    exit 1
fi

BACKUP_AGE=$(($(date +%s) - $(stat -c %Y "$LATEST_BACKUP")))
MAX_AGE=$((24 * 3600)) # 24小时

if [ $BACKUP_AGE -gt $MAX_AGE ]; then
    echo "[$(date)] WARNING: Backup is $(($BACKUP_AGE/3600)) hours old" | mail -s "MongoDB Backup Alert" $ALERT_EMAIL
fi

# 验证备份完整性
if ! tar -tzf "$LATEST_BACKUP" > /dev/null 2>&1; then
    echo "[$(date)] CRITICAL: Backup file is corrupt: $LATEST_BACKUP" | mail -s "MongoDB Backup Alert" $ALERT_EMAIL
fi

echo "[$(date)] Backup check passed: $LATEST_BACKUP" >> $LOG_FILE

第六部分:常见误区与规避方法

6.1 误区1:备份不验证

问题:很多团队创建备份后从不测试恢复,直到真正需要时才发现备份无效。

解决方案

  • 每月至少执行一次完整的恢复测试
  • 自动化验证流程
  • 保留测试恢复的详细日志
# 自动化恢复测试脚本
#!/bin/bash
TEST_RESTORE_DIR="/tmp/restore_test_$(date +%s)"
mkdir -p $TEST_RESTORE_DIR

# 随机选择一个备份
BACKUP_FILE=$(find /backup/mongodb -name "*.tar.gz" | shuf -n 1)

# 尝试恢复到临时实例
mongod --dbpath $TEST_RESTORE_DIR --port 27018 --fork --logpath $TEST_RESTORE_DIR/mongod.log

if mongorestore --port 27018 $BACKUP_FILE; then
    echo "Restore test PASSED: $BACKUP_FILE"
    # 验证数据完整性
    mongo --port 27018 --eval "db.adminCommand({listDatabases:1})" > /dev/null
    echo "Data integrity check PASSED"
else
    echo "Restore test FAILED: $BACKUP_FILE" >&2
    exit 1
fi

# 清理
mongod --dbpath $TEST_RESTORE_DIR --shutdown
rm -rf $TEST_RESTORE_DIR

6.2 误区2:备份窗口过大导致性能问题

问题:在业务高峰期执行全量备份,导致数据库性能严重下降。

解决方案

  • 在业务低峰期执行备份
  • 从Secondary节点备份
  • 使用文件系统快照技术
# 检查副本集状态,确保从Secondary备份
#!/bin/bash
PRIMARY=$(mongo --eval "db.isMaster().primary" --quiet)
SECONDARIES=$(mongo --eval "db.isMaster().hosts" --quiet | grep -v "$PRIMARY")

for node in $SECONDARIES; do
    # 检查节点延迟
    LAG=$(mongo --host $node --eval "rs.status().members.find(m => m.name === '$node').optimeDate" --quiet)
    if [ "$LAG" -lt "60" ]; then # 延迟小于60秒
        mongodump --host $node --out /backup/mongodb/
        break
    fi
done

6.3 误区3:忽略配置和索引备份

问题:只备份数据,不备份索引和配置,导致恢复后性能严重下降。

解决方案

  • 备份system.indexes和system.profile集合
  • 记录索引创建语句
  • 备份MongoDB配置文件
#!/bin/bash
# 完整备份脚本(包含配置和索引)

BACKUP_DIR="/backup/mongodb/full_$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR

# 1. 备份所有数据库(包括系统库)
mongodump --host secondary --out $BACKUP_DIR/dump --oplog

# 2. 导出索引信息
mongo --host secondary --eval "db.getSiblingDB('admin').system.indexes.find().toArray()" > $BACKUP_DIR/indexes.json

# 3. 备份配置文件
cp /etc/mongod.conf $BACKUP_DIR/

# 4. 记录当前oplog时间戳
OPLOG_TS=$(mongo --host secondary --eval "db.getSiblingDB('local').oplog.rs.find().sort({\$natural:-1}).limit(1).next().ts" --quiet)
echo $OPLOG_TS > $BACKUP_DIR/oplog_timestamp.txt

# 5. 创建恢复指南
cat > $BACKUP_DIR/README.md <<EOF
# 恢复指南

## 恢复步骤
1. 停止MongoDB服务
2. 清空数据目录
3. 恢复数据: mongorestore --oplogReplay --dir $BACKUP_DIR/dump
4. 恢复索引: mongo < $BACKUP_DIR/indexes.json
5. 重启MongoDB

## 注意事项
- 恢复后需要重新创建用户
- 检查oplog时间戳: $OPLOG_TS
- 验证索引是否完整
EOF

6.4 误区4:备份存储单一化

问题:所有备份都存储在同一个物理位置,一旦发生火灾、洪水等灾害将全部丢失。

解决方案

  • 遵循3-2-1原则:3份数据,2种介质,1份异地
  • 使用云存储作为异地备份
  • 定期测试异地恢复
#!/bin/bash
# 3-2-1备份策略实现

LOCAL_BACKUP="/backup/mongodb"
REMOTE_BACKUP="s3://my-backup-bucket/mongodb"
ARCHIVE_DIR="/archive/mongodb"

# 1. 创建本地备份
mongodump --out $LOCAL_BACKUP/current

# 2. 压缩并加密
tar -czf - $LOCAL_BACKUP/current | openssl enc -aes-256-cbc -salt -out $LOCAL_BACKUP/backup_$(date +%Y%m%d).tar.gz.enc -k "YOUR_ENCRYPTION_KEY"

# 3. 上传到云端
aws s3 cp $LOCAL_BACKUP/backup_$(date +%Y%m%d).tar.gz.enc $REMOTE_BACKUP/

# 4. 移动到长期归档(每月一次)
if [ $(date +%d) -eq 01 ]; then
    cp $LOCAL_BACKUP/backup_$(date +%Y%m%d).tar.gz.enc $ARCHIVE_DIR/
fi

# 5. 清理旧备份(保留策略)
find $LOCAL_BACKUP -name "*.enc" -mtime +7 -delete
aws s3 ls $REMOTE_BACKUP/ | awk '{print $4}' | while read file; do
    # 保留最近30天的云端备份
    if [[ $file =~ backup_([0-9]{8}).tar.gz.enc ]]; then
        backup_date=${BASH_REMATCH[1]}
        days_old=$(( ( $(date +%s) - $(date -d "$backup_date" +%s) ) / 86400 ))
        if [ $days_old -gt 30 ]; then
            aws s3 rm $REMOTE_BACKUP/$file
        fi
    fi
done

6.5 误区5:备份权限管理不当

问题:使用过高权限的账号进行备份,存在安全风险。

解决方案

  • 创建专用的备份角色
  • 遵循最小权限原则
  • 定期轮换备份凭证
# 创建备份专用角色
mongo admin --eval "
db.createRole({
    role: 'backupRole',
    privileges: [
        {
            resource: { db: '', collection: '' },
            actions: ['find', 'listDatabases', 'listCollections']
        }
    ],
    roles: []
});

db.createUser({
    user: 'backupUser',
    pwd: 'secure_password',
    roles: ['backupRole']
});
"

# 使用备份用户进行备份
mongodump --username backupUser --password secure_password --authenticationDatabase admin --out /backup/

第七部分:备份性能优化

7.1 并行备份策略

对于大型数据库,可以使用并行备份提高速度:

#!/bin/bash
# 并行备份所有数据库

DATABASES=$(mongo --eval "db.adminCommand('listDatabases').databases" --quiet | grep -oP '"name":"\K[^"]+')

for db in $DATABASES; do
    # 每个数据库一个备份进程
    mongodump --db $db --out /backup/mongodb/parallel_$db &
done

wait # 等待所有进程完成

# 合并备份目录
mkdir -p /backup/mongodb/complete
for db in $DATABASES; do
    mv /backup/mongodb/parallel_$db/$db /backup/mongodb/complete/
done
rm -rf /backup/mongodb/parallel_*

7.2 压缩与存储优化

# 使用pigz进行并行压缩(比gzip快)
mongodump --out /tmp/backup | pigz > /backup/mongodb/backup.tar.gz

# 使用zstd进行高效压缩
mongodump --out /tmp/backup
tar -cf - /tmp/backup | zstd -19 -o /backup/mongodb/backup.tar.zst

# 恢复时解压
zstd -d /backup/mongodb/backup.tar.zst -c | tar -xf - -C /tmp/
mongorestore /tmp/backup

7.3 备份带宽限制

在带宽受限的环境中,可以限制备份速度:

# 使用trickle限制带宽(需要安装trickle)
trickle -d 1000 mongodump --out /backup/mongodb/

# 或者使用rsync的bwlimit
rsync -av --bwlimit=1000 /data/db/ /backup/mongodb/

第八部分:灾难恢复计划

8.1 灾难恢复场景分类

灾难类型 影响 恢复时间目标(RTO) 恢复点目标(RPO)
误删除数据 部分数据丢失 分钟级 小时级
磁盘损坏 单节点不可用 小时级 小时级
数据中心故障 整个集群不可用 天级 小时级
勒索软件 数据加密 天级 天级

8.2 分级恢复策略

#!/bin/bash
# 分级恢复脚本

RESTORE_LEVEL=$1 # 1=快速恢复,2=完整恢复,3=灾难恢复

case $RESTORE_LEVEL in
    1)
        # 快速恢复:从最近的快照恢复
        LATEST_SNAPSHOT=$(aws s3 ls s3://my-backup-bucket/mongodb/ | sort | tail -1 | awk '{print $4}')
        aws s3 cp s3://my-backup-bucket/mongodb/$LATEST_SNAPSHOT /tmp/
        mongorestore --oplogReplay /tmp/$LATEST_SNAPSHOT
        ;;
    2)
        # 完整恢复:从指定时间点恢复
        echo "请输入要恢复的时间点 (格式: YYYY-MM-DD HH:MM:SS)"
        read -p "时间点: " RESTORE_TIME
        
        # 找到包含该时间点的备份
        # ... 恢复逻辑 ...
        ;;
    3)
        # 灾难恢复:从异地备份恢复
        echo "执行灾难恢复流程..."
        # 1. 从云端下载完整备份
        aws s3 sync s3://my-backup-bucket/mongodb/ /tmp/disaster_recovery/
        
        # 2. 恢复config server(如果是分片集群)
        # 3. 恢复分片
        # 4. 验证数据一致性
        ;;
esac

8.3 恢复后验证

#!/bin/bash
# 恢复后验证脚本

# 1. 检查数据库状态
mongo --eval "db.adminCommand({listDatabases:1})" > /dev/null
if [ $? -ne 0 ]; then
    echo "数据库无法访问"
    exit 1
fi

# 2. 验证数据量
EXPECTED_COUNT=$1
ACTUAL_COUNT=$(mongo myapp --eval "db.users.countDocuments()" --quiet)
if [ "$ACTUAL_COUNT" -eq "$EXPECTED_COUNT" ]; then
    echo "数据量验证通过"
else
    echo "数据量不匹配: 期望 $EXPECTED_COUNT, 实际 $ACTUAL_COUNT"
fi

# 3. 验证索引
mongo myapp --eval "db.users.getIndexes()" | grep -q "idx_email" && echo "索引验证通过" || echo "索引缺失"

# 4. 性能基准测试
mongosh myapp --eval "
db.users.find({email: 'test@example.com'}).explain('executionStats')
" | grep -q "IXSCAN" && echo "查询性能正常" || echo "查询性能异常"

第九部分:备份策略演进路线

9.1 初级阶段(单节点/开发环境)

  • 每日全量备份
  • 本地存储
  • 手动恢复测试

9.2 中级阶段(生产副本集)

  • 从Secondary节点备份
  • 每周全量+每日增量
  • 本地+云端存储
  • 自动化监控

9.3 高级阶段(分片集群)

  • 一致性快照备份
  • 多云存储
  • 自动化测试
  • 灾难恢复演练

9.4 企业级阶段

  • 实时备份(基于Oplog)
  • 多地域复制
  • 备份即服务(BaaS)
  • 合规性审计

第十部分:总结与最佳实践清单

10.1 备份策略检查清单

  • [ ] 是否定期测试恢复流程?
  • [ ] 备份是否包含系统配置和索引?
  • [ ] 是否有多个备份副本(3-2-1原则)?
  • [ ] 备份是否加密?
  • [ ] 是否有明确的RTO和RPO目标?
  • [ ] 是否监控备份状态和告警?
  • [ ] 备份权限是否遵循最小权限原则?
  • [ ] 是否有文档化的恢复流程?
  • [ ] 是否定期进行灾难恢复演练?
  • [ ] 备份策略是否随业务变化更新?

10.2 关键指标监控

# 监控关键指标
#!/bin/bash

# 1. 备份成功率
BACKUP_SUCCESS_RATE=$(grep -c "Backup completed" /var/log/mongodb_backup.log 2>/dev/null || echo 0)
echo "备份成功率: $BACKUP_SUCCESS_RATE"

# 2. 备份大小趋势
du -sh /backup/mongodb/* | sort -h | tail -5

# 3. 恢复时间
grep "Restore completed" /var/log/mongodb_restore.log 2>/dev/null | awk '{print $NF}' | sort -n | tail -5

# 4. 存储成本
aws s3 ls --summarize --human-readable s3://my-backup-bucket/mongodb/ | grep "Total Size"

10.3 持续改进

备份策略不是一成不变的,应该:

  • 每季度审查一次
  • 根据业务增长调整
  • 学习行业最佳实践
  • 从故障中吸取教训

结语

MongoDB备份策略是数据安全的最后防线。一个完善的备份方案需要综合考虑业务需求、技术限制和成本因素。记住,备份的价值只有在恢复时才能真正体现。投入时间和资源建立可靠的备份体系,是每个负责任的技术团队必须完成的功课。

从今天开始,检查你现有的备份策略,填补空白,测试恢复流程。因为在数据安全这件事上,预防永远比治疗更便宜。