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

在现代应用架构中,MongoDB作为领先的NoSQL数据库,承载着越来越多关键业务数据。想象一下,如果您的电商网站突然无法访问,或者用户数据意外丢失,后果将不堪设想。这就是为什么制定完善的MongoDB备份策略不是可选项,而是必选项。

MongoDB备份不仅仅是简单的数据复制,它是一个涉及数据完整性、业务连续性、灾难恢复和合规性的综合体系。根据行业统计,数据丢失的主要原因包括硬件故障(44%)、人为错误(32%)、软件故障(14%)和自然灾害(10%)。一个健全的备份策略能够确保在任何情况下都能快速恢复业务。

本文将从基础概念开始,逐步深入到高级实践,为您提供一套完整的MongoDB备份解决方案。无论您是刚接触MongoDB的开发者,还是负责企业级数据库运维的DBA,都能从中获得实用的指导。

MongoDB备份基础概念

MongoDB数据存储机制概述

要理解备份,首先需要了解MongoDB是如何存储数据的。MongoDB使用B-Tree索引结构将数据存储在数据文件(.wt文件)中,这些文件位于dbPath指定的目录下。每个数据库对应一个独立的目录,集合数据存储在对应的.ns和.wt文件中。

MongoDB的写操作首先写入内存(WiredTiger引擎)或直接写入磁盘(MMAPv1),然后通过journaling机制确保持久性。理解这一点对于制定备份策略至关重要,因为不同的备份方法对数据存储机制的依赖程度不同。

备份的类型和目标

MongoDB备份主要分为两类:

  1. 物理备份:直接复制底层数据文件,速度快但需要数据库停机或特定工具支持
  2. 逻辑备份:通过导出数据内容(如JSON、BSON格式),灵活性高但速度较慢

备份的目标包括:

  • 数据保护:防止数据丢失
  • 灾难恢复:应对硬件故障、自然灾害
  • 数据迁移:在不同环境间移动数据
  • 合规性:满足法规要求
  • 开发测试:为测试环境提供真实数据

基础备份方法

mongodump和mongorestore:逻辑备份的核心工具

mongodump是MongoDB官方提供的逻辑备份工具,它通过连接到运行的MongoDB实例,查询数据并导出为BSON格式。这是最常用且最灵活的备份方法。

mongodump基本用法

# 基本备份所有数据库
mongodump --host localhost --port 27017 --out /backup/mongodb/$(date +%Y%m%d)

# 备份指定数据库
mongodump --db myapp --out /backup/mongodb/myapp_$(date +%Y%m%d)

# 备份指定集合
mongodump --db myapp --collection users --out /backup/mongodb/users_$(date +%Y%m%d)

# 使用认证备份
mongodump --host cluster.example.com --username backupUser --password "securepass" --authenticationDatabase admin --out /backup/mongodb/

# 压缩备份(节省空间)
mongodump --host localhost --gzip --out /backup/mongodb/compressed_$(date +%Y%m%d)

# 增量备份(配合oplog)
mongodump --host localhost --oplog --out /backup/mongodb/incremental_$(date +%Y%m%d)

mongorestore基本用法

# 恢复整个备份
mongorestore --host localhost --port 27017 /backup/mongodb/20240101

# 恢复指定数据库
mongorestore --db myapp /backup/mongodb/myapp_20240101/myapp

# 恢复指定集合
mongorestore --db myapp --collection users /backup/mongodb/users_20240101/myapp/users.bson

# 恢复时覆盖现有数据
mongorestore --drop --db myapp /backup/mongodb/myapp_20240101/myapp

# 使用认证恢复
mongorestore --host cluster.example.com --username restoreUser --password "securepass" --authenticationDatabase admin /backup/mongodb/20240101

# 恢复压缩备份
mongorestore --gzip --db myapp /backup/mongodb/compressed_20240101/myapp

实际应用示例:创建日常备份脚本

#!/bin/bash
# MongoDB日常备份脚本

# 配置变量
BACKUP_DIR="/backup/mongodb/daily"
MONGO_HOST="localhost"
MONGO_PORT="27017"
MONGO_USER="backupUser"
MONGO_PASS="securePassword"
RETENTION_DAYS=7

# 创建备份目录
mkdir -p $BACKUP_DIR/$(date +%Y%m%d)

# 执行备份
mongodump --host $MONGO_HOST --port $MONGO_PORT \
          --username $MONGO_USER --password $MONGO_PASS \
          --authenticationDatabase admin \
          --gzip \
          --out $BACKUP_DIR/$(date +%Y%m%d)

# 检查备份是否成功
if [ $? -eq 0 ]; then
    echo "$(date): Backup completed successfully" >> /var/log/mongodb_backup.log
    
    # 删除过期备份
    find $BACKUP_DIR -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \;
    
    # 发送成功通知
    echo "MongoDB daily backup completed successfully" | mail -s "Backup Success" admin@example.com
else
    echo "$(date): Backup failed" >> /var/log/mongodb_backup.log
    echo "MongoDB daily backup failed" | mail -s "Backup Failed" admin@example.com
    exit 1
fi

文件系统快照:物理备份的快速方案

文件系统快照提供了近乎瞬时的备份能力,特别适合大型数据库。MongoDB支持多种快照技术,包括LVM快照、ZFS快照和云服务商提供的快照功能。

LVM快照示例

#!/bin/bash
# LVM快照备份MongoDB

# 配置
MONGO_DBPATH="/var/lib/mongodb"
SNAPSHOT_SIZE="10G"
BACKUP_DIR="/backup/mongodb/snapshots"

# 1. 确保MongoDB使用journaling
mongo --eval "db.adminCommand({getParameter:1, journalCommitInterval:1})"

# 2. 刷新并锁定数据库(写锁)
mongo --eval "db.fsyncLock()"

# 3. 创建LVM快照
lvcreate --size $SNAPSHOT_SIZE --snapshot --name mongo-snap /dev/vg0/mongo-lv

# 4. 解锁数据库
mongo --eval "db.fsyncUnlock()"

# 5. 挂载快照
mkdir -p /mnt/mongo-snap
mount /dev/vg0/mongo-snap /mnt/mongo-snap

# 6. 复制数据到备份目录
rsync -av /mnt/mongo-snap/ $BACKUP_DIR/$(date +%Y%m%d_%H%M%S)/

# 7. 清理
umount /mnt/mongo-snap
lvremove -f /dev/vg0/mongo-snap

echo "LVM snapshot backup completed"

ZFS快照示例

#!/bin/bash
# ZFS快照备份MongoDB

# 配置
ZFS_POOL="tank/mongodb"
SNAPSHOT_NAME="backup-$(date +%Y%m%d_%H%M%S)"

# 1. 创建ZFS快照
zfs snapshot $ZFS_POOL@$SNAPSHOT_NAME

# 2. 将快照发送到备份服务器
zfs send $ZFS_POOL@$SNAPSHOT_NAME | ssh backup-server "zfs receive tank/mongodb-backup/$SNAPSHOT_NAME"

# 3. 清理旧快照(保留最近7天)
zfs list -t snapshot -o name,creation | grep $ZFS_POOL | awk '{print $1}' | head -n -7 | xargs -I {} zfs destroy {}

echo "ZFS snapshot backup completed"

mongodump vs 文件系统备份:如何选择?

特性 mongodump 文件系统备份
备份速度 较慢(需要查询数据) 极快(秒级完成)
恢复速度 较慢(需要重建索引) 极快(立即可用)
灵活性 高(可选择集合、文档) 低(必须备份整个数据库)
版本兼容性 好(可跨版本恢复) 差(需相同版本)
存储空间 较小(可压缩) 较大(完整文件)
在线备份 支持 需要快照或锁
适用场景 中小型数据库、需要选择性恢复 大型数据库、快速恢复需求

高级备份策略

副本集备份:利用从节点的优势

在副本集环境中,最佳实践是从Secondary节点执行备份,这样可以避免影响Primary节点的性能。这种方法被称为”备份友好型”配置。

副本集备份策略

#!/bin/bash
# 从副本集Secondary节点备份

# 配置
REPLICA_SET="rs0"
BACKUP_NODE="secondary1.example.com"
BACKUP_DIR="/backup/mongodb/replica_set"
MONGO_USER="backupUser"
MONGO_PASS="securepass"

# 1. 检查节点状态,确保是Secondary
ROLE=$(mongo --host $BACKUP_NODE --eval "db.isMaster().ismaster" --quiet)
if [ "$ROLE" = "true" ]; then
    echo "Error: Connected to Primary, aborting backup"
    exit 1
fi

# 2. 执行备份
mongodump --host $BACKUP_NODE --port 27017 \
          --username $MONGO_USER --password $MONGO_PASS \
          --authenticationDatabase admin \
          --oplog \
          --gzip \
          --out $BACKUP_DIR/$(date +%Y%m%d)

# 3. 验证备份完整性
mongorestore --host $BACKUP_NODE --username $MONGO_USER --password $MONGO_PASS \
             --authenticationDatabase admin \
             --dryRun \
             $BACKUP_DIR/$(date +%Y%m%d)

echo "Replica set backup completed from secondary node"

备份窗口优化

对于高负载的副本集,可以使用以下策略优化备份窗口:

#!/bin/bash
# 智能备份窗口选择

# 获取当前复制延迟
PRIMARY_NODE="primary.example.com"
SECONDARY_NODE="secondary1.example.com"

# 检查复制延迟(秒)
DELAY=$(mongo --host $SECONDARY_NODE --eval "rs.printSlaveReplicationInfo()" --quiet | grep "sec" | awk '{print $2}' | sed 's/s//')

# 如果延迟超过阈值,等待或选择其他节点
if [ "$DELAY" -gt 300 ]; then
    echo "Replication delay too high: ${DELAY}s, waiting..."
    # 可以选择其他延迟较低的节点
    SECONDARY_NODE="secondary2.example.com"
fi

# 执行备份
mongodump --host $SECONDARY_NODE --oplog --gzip --out /backup/mongodb/$(date +%Y%m%d)

分片集群备份:协调多分片的挑战

分片集群的备份需要协调多个分片和配置服务器,确保数据一致性。最简单的方法是备份所有分片和配置服务器,但更高效的方法是使用”备份窗口”和”一致性快照”。

分片集群备份策略

#!/bin/bash
# MongoDB分片集群备份

# 配置
SHARDS=("shard1.example.com:27018" "shard2.example.com:27018" "shard3.example.com:27018")
CONFIG_SERVER="config1.example.com:27019"
MONGOS="mongos.example.com:27017"
BACKUP_DIR="/backup/mongodb/sharded_cluster"
MONGO_USER="backupUser"
MONGO_PASS="securepass"

# 1. 在所有分片上设置备份窗口
for SHARD in "${SHARDS[@]}"; do
    mongo --host $SHARD --eval "db.adminCommand({setParameter:1, backupWindow: true})"
done

# 2. 在配置服务器上设置备份窗口
mongo --host $CONFIG_SERVER --eval "db.adminCommand({setParameter:1, backupWindow: true})"

# 3. 获取所有分片的备份信息
BACKUP_INFO_FILE="$BACKUP_DIR/backup_info_$(date +%Y%m%d_%H%M%S).json"
mongo --host $MONGOS --eval "db.adminCommand({listShards:1})" > $BACKUP_INFO_FILE

# 4. 并行备份所有分片
for SHARD in "${SHARDS[@]}"; do
    SHARD_NAME=$(echo $SHARD | cut -d':' -f1)
    mongodump --host $SHARD --username $MONGO_USER --password $MONGO_PASS \
              --authenticationDatabase admin \
              --gzip \
              --out $BACKUP_DIR/shards/$SHARD_NAME_$(date +%Y%m%d) &
done

# 5. 备份配置服务器
mongodump --host $CONFIG_SERVER --username $MONGO_USER --password $MONGO_PASS \
          --authenticationDatabase admin \
          --gzip \
          --out $BACKUP_DIR/config_$(date +%Y%m%d) &

# 6. 等待所有备份完成
wait

# 7. 清除备份窗口
for SHARD in "${SHARDS[@]}"; do
    mongo --host $SHARD --eval "db.adminCommand({setParameter:1, backupWindow: false})"
done
mongo --host $CONFIG_SERVER --eval "db.adminCommand({setParameter:1, backupWindow: false})"

echo "Sharded cluster backup completed"

增量备份与时间点恢复(PITR)

增量备份只备份自上次备份以来发生变化的数据,大大节省存储空间和备份时间。MongoDB的oplog(操作日志)是实现增量备份的关键。

增量备份实现

#!/bin/bash
# MongoDB增量备份

# 配置
BASE_BACKUP_DIR="/backup/mongodb/incremental"
LAST_OPLOG_FILE="$BASE_BACKUP_DIR/last_oplog.txt"
MONGO_HOST="localhost"
MONGO_USER="backupUser"
MONGO_PASS="securepass"

# 1. 获取上次备份的oplog时间戳
if [ -f "$LAST_OPLOG_FILE" ]; then
    LAST_TS=$(cat $LAST_OPLOG_FILE)
else
    # 首次备份,获取当前oplog起始时间
    LAST_TS=$(mongo --host $MONGO_HOST --username $MONGO_USER --password $MONGO_PASS \
                    --authenticationDatabase admin \
                    --eval "db.oplog.rs.find().sort({\$natural:1}).limit(1).next().ts" --quiet)
fi

# 2. 执行增量备份
BACKUP_NAME="inc_$(date +%Y%m%d_%H%M%S)"
mongodump --host $MONGO_HOST --port 27017 \
          --username $MONGO_USER --password $MONGO_PASS \
          --authenticationDatabase admin \
          --oplog --gzip \
          --out $BASE_BACKUP_DIR/$BACKUP_NAME

# 3. 记录本次oplog结束时间
CURRENT_TS=$(mongo --host $MONGO_HOST --username $MONGO_USER --password $MONGO_PASS \
                   --authenticationDatabase admin \
                   --eval "db.oplog.rs.find().sort({\$natural:-1}).limit(1).next().ts" --quiet)

# 4. 保存时间戳用于下次备份
echo $CURRENT_TS > $LAST_OPLOG_FILE

# 5. 创建增量备份元数据
cat > $BASE_BACKUP_DIR/$BACKUP_NAME/metadata.json << EOF
{
    "type": "incremental",
    "base_timestamp": "$LAST_TS",
    "current_timestamp": "$CURRENT_TS",
    "created": "$(date -Iseconds)",
    "parent": "$(basename $(ls -dt $BASE_BACKUP_DIR/inc_* | head -2 | tail -1))"
}
EOF

echo "Incremental backup completed: $BACKUP_NAME"

时间点恢复(PITR)

#!/bin/bash
# MongoDB时间点恢复

# 配置
BACKUP_DIR="/backup/mongodb/incremental"
RESTORE_POINT="2024-01-15T14:30:00"
TARGET_DB="myapp"
RESTORE_HOST="localhost"

# 1. 找到包含目标时间点的备份
find_backup_for_point() {
    local target_time=$1
    local backup_list=$(find $BACKUP_DIR -name "metadata.json" -exec cat {} \; | grep -A1 "current_timestamp")
    # 这里简化处理,实际需要更复杂的逻辑
    echo "inc_20240115_140000"  # 示例
}

BACKUP_TO_RESTORE=$(find_backup_for_point "$RESTORE_POINT")

# 2. 恢复基础备份
mongorestore --host $RESTORE_HOST --username restoreUser --password "restorepass" \
             --authenticationDatabase admin \
             --gzip \
             $BACKUP_DIR/$BACKUP_TO_RESTORE

# 3. 应用oplog到指定时间点
OPLOG_FILE="$BACKUP_DIR/$BACKUP_TO_RESTORE/oplog.bson"
if [ -f "$OPLOG_FILE" ]; then
    # 提取oplog到指定时间点
    mongorestore --host $RESTORE_HOST --username restoreUser --password "restorepass" \
                 --authenticationDatabase admin \
                 --oplogReplay --oplogLimit "$RESTORE_POINT" \
                 $BACKUP_DIR/$BACKUP_TO_RESTORE
fi

echo "Point-in-time recovery completed to: $RESTORE_POINT"

云原生备份方案

对于部署在AWS、Azure或GCP的MongoDB,可以利用云服务商的快照功能实现高效备份。

AWS EBS快照备份

#!/bin/bash
# AWS EBS快照备份MongoDB

# 配置
INSTANCE_ID="i-0abcd1234efgh5678"
VOLUME_ID="vol-0123456789abcdef0"
MONGO_HOST="mongodb.example.com"
MONGO_USER="backupUser"
MONGO_PASS="securepass"
SNAPSHOT_DESCRIPTION="MongoDB Backup $(date +%Y-%m-%d)"

# 1. 刷新数据并锁定(可选)
mongo --host $MONGO_HOST --eval "db.fsyncLock()"

# 2. 创建EBS快照
SNAPSHOT_ID=$(aws ec2 create-snapshot \
    --volume-id $VOLUME_ID \
    --description "$SNAPSHOT_DESCRIPTION" \
    --query 'SnapshotId' \
    --output text)

# 3. 等待快照完成
aws ec2 wait snapshot-completed --snapshot-ids $SNAPSHOT_ID

# 4. 解锁数据库
mongo --host $MONGO_HOST --eval "db.fsyncUnlock()"

# 5. 添加标签
aws ec2 create-tags \
    --resources $SNAPSHOT_ID \
    --tags Key=Name,Value=MongoDB-Backup Key=Environment,Value=Production Key=Retention,Value=30days

# 6. 清理旧快照(保留最近30天)
aws ec2 describe-snapshots \
    --filters "Name=tag:Name,Values=MongoDB-Backup" \
    --query 'Snapshots[?StartTime<`'$(date -d '30 days ago' +%Y-%m-%d)'`'].SnapshotId' \
    --output text | xargs -I {} aws ec2 delete-snapshot --snapshot-id {}

echo "AWS EBS snapshot created: $SNAPSHOT_ID"

MongoDB Atlas云备份

如果您使用MongoDB Atlas,可以利用其内置的云备份功能:

#!/bin/bash
# MongoDB Atlas备份管理

# 配置
ATLAS_PROJECT_ID="1234567890abcdef"
ATLAS_API_PUBLIC_KEY="your-public-key"
ATLAS_API_PRIVATE_KEY="your-private-key"
ATLAS_CLUSTER_NAME="myapp-cluster"

# 1. 获取备份快照列表
curl -X GET \
  "https://cloud.mongodb.com/api/atlas/v1.0/groups/$ATLAS_PROJECT_ID/clusters/$ATLAS_CLUSTER_NAME/backup/snapshots" \
  -u "$ATLAS_API_PUBLIC_KEY:$ATLAS_API_PRIVATE_KEY" > snapshots.json

# 2. 创建新快照(如果需要)
curl -X POST \
  "https://cloud.mongodb.com/api/atlas/v1.0/groups/$ATLAS_PROJECT_ID/clusters/$ATLAS_CLUSTER_NAME/backup/snapshots" \
  -u "$ATLAS_API_PUBLIC_KEY:$ATLAS_API_PRIVATE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"retentionInDays": 7}'

# 3. 下载快照(用于迁移)
SNAPSHOT_ID="612a3e5f6f6f6f6f6f6f6f6f"
curl -X GET \
  "https://cloud.mongodb.com/api/atlas/v1.0/groups/$ATLAS_PROJECT_ID/clusters/$ATLAS_CLUSTER_NAME/backup/snapshots/$SNAPSHOT_ID/download" \
  -u "$ATLAS_API_PUBLIC_KEY:$ATLAS_API_PRIVATE_KEY" > download_link.json

echo "Atlas backup operations completed"

备份自动化与监控

使用cron定时任务

# /etc/cron.d/mongodb-backup
# MongoDB备份定时任务

# 每天凌晨2点执行全量备份
0 2 * * * root /usr/local/bin/mongodb_backup_full.sh

# 每4小时执行增量备份
0 */4 * * * root /usr/local/bin/mongodb_backup_incremental.sh

# 每周日执行一次恢复测试
0 3 * * 0 root /usr/local/bin/mongodb_restore_test.sh

# 每月1号清理超过90天的备份
0 1 1 * * root /usr/local/bin/mongodb_backup_cleanup.sh

备份监控脚本

#!/bin/bash
# MongoDB备份监控

# 配置
LOG_FILE="/var/log/mongodb_backup_monitor.log"
ALERT_EMAIL="admin@example.com"
BACKUP_DIRS=("/backup/mongodb/daily" "/backup/mongodb/incremental")

# 检查最近24小时的备份
check_backup_age() {
    local dir=$1
    local latest=$(find $dir -type f -name "*.bson" -o -name "*.gz" 2>/dev/null | head -1)
    
    if [ -z "$latest" ]; then
        echo "ERROR: No backups found in $dir" | tee -a $LOG_FILE
        return 1
    fi
    
    local age=$(($(date +%s) - $(stat -c %Y "$latest")))
    local max_age=86400  # 24小时
    
    if [ $age -gt $max_age ]; then
        echo "WARNING: Backup in $dir is $(($age/3600)) hours old" | tee -a $LOG_FILE
        return 1
    fi
    
    echo "OK: Backup in $dir is recent" | tee -a $LOG_FILE
    return 0
}

# 检查备份大小
check_backup_size() {
    local dir=$1
    local size=$(du -sb $dir 2>/dev/null | cut -f1)
    local min_size=1000000  # 1MB
    
    if [ $size -lt $min_size ]; then
        echo "WARNING: Backup size in $dir is too small: $size bytes" | tee -a $LOG_FILE
        return 1
    fi
    
    echo "OK: Backup size in $dir is $size bytes" | tee -a $LOG_FILE
    return 0
}

# 检查备份完整性
check_backup_integrity() {
    local dir=$1
    local bson_file=$(find $dir -name "*.bson" 2>/dev/null | head -1)
    
    if [ -z "$bson_file" ]; then
        echo "ERROR: No BSON file found in $dir" | tee -a $LOG_FILE
        return 1
    fi
    
    # 尝试读取BSON文件头部
    if head -c 1024 "$bson_file" > /dev/null 2>&1; then
        echo "OK: Backup integrity check passed for $dir" | tee -a $LOG_FILE
        return 0
    else
        echo "ERROR: Backup integrity check failed for $dir" | tee -a $LOG_FILE
        return 1
    fi
}

# 主监控逻辑
main() {
    local all_ok=true
    
    for dir in "${BACKUP_DIRS[@]}"; do
        echo "=== Checking $dir ===" | tee -a $LOG_FILE
        
        if ! check_backup_age "$dir"; then
            all_ok=false
        fi
        
        if ! check_backup_size "$dir"; then
            all_ok=false
        fi
        
        if ! check_backup_integrity "$dir"; then
            all_ok=false
        fi
        
        echo "" | tee -a $LOG_FILE
    done
    
    if [ "$all_ok" = false ]; then
        echo "Backup check failed - sending alert" | tee -a $LOG_FILE
        cat $LOG_FILE | mail -s "MongoDB Backup Alert" $ALERT_EMAIL
        exit 1
    else
        echo "All backup checks passed" | tee -a $LOG_FILE
        exit 0
    fi
}

main "$@"

备份验证与测试恢复

#!/bin/bash
# MongoDB备份验证与测试恢复

# 配置
BACKUP_DIR="/backup/mongodb/daily"
TEST_DB="backup_test_$(date +%Y%m%d)"
TEST_HOST="localhost"
TEST_PORT="27018"  # 使用不同端口避免冲突
MONGO_USER="testUser"
MONGO_PASS="testpass"

# 1. 创建测试实例(使用临时目录)
TEST_DBPATH="/tmp/mongodb_test_$$"
mkdir -p $TEST_DBPATH

# 2. 启动临时MongoDB实例
mongod --dbpath $TEST_DBPATH --port $TEST_PORT --fork --logpath $TEST_DBPATH/mongod.log

# 3. 等待启动
sleep 5

# 4. 找到最新的备份
LATEST_BACKUP=$(ls -td $BACKUP_DIR/*/ | head -1)

# 5. 恢复到测试实例
mongorestore --host localhost --port $TEST_PORT \
             --gzip \
             $LATEST_BACKUP

# 6. 验证数据
mongo --host localhost --port $TEST_PORT --eval "
    dbs = db.adminCommand('listDatabases').databases;
    print('Restored databases:');
    dbs.forEach(function(db) {
        print(' - ' + db.name + ' (' + (db.sizeOnDisk/1024/1024).toFixed(2) + ' MB)');
    });
    
    // 检查关键集合
    if (db.getSiblingDB('myapp').users.count() > 0) {
        print('✓ Users collection restored successfully');
    } else {
        print('✗ Users collection is empty');
    }
"

# 7. 清理测试实例
mongo --host localhost --port $TEST_PORT --eval "db.getSiblingDB('$TEST_DB').dropDatabase()"
mongod --dbpath $TEST_DBPATH --port $TEST_PORT --shutdown
rm -rf $TEST_DBPATH

echo "Backup validation completed"

备份存储与安全管理

备份存储策略

3-2-1备份法则

3-2-1法则是数据保护的黄金标准:

  • 3份数据副本
  • 2种不同存储介质
  • 1份异地备份
#!/bin/bash
# 实现3-2-1备份策略

# 配置
LOCAL_BACKUP="/backup/mongodb"
REMOTE_BACKUP="backup-server:/remote/backup/mongodb"
S3_BUCKET="s3://my-mongodb-backups"

# 1. 本地备份(第一份)
mongodump --out $LOCAL_BACKUP/$(date +%Y%m%d)

# 2. 复制到远程服务器(第二份)
rsync -avz $LOCAL_BACKUP/$(date +%Y%m%d)/ $REMOTE_BACKUP/$(date +%Y%m%d)/

# 3. 上传到S3(第三份,异地)
aws s3 sync $LOCAL_BACKUP/$(date +%Y%m%d)/ $S3_BUCKET/$(date +%Y%m%d)/ --storage-class GLACIER

# 4. 验证所有副本
echo "Verifying backup copies..."
# 本地校验
find $LOCAL_BACKUP/$(date +%Y%m%d)/ -name "*.bson" -exec md5sum {} \; > /tmp/local_checksum.txt
# 远程校验(通过SSH)
ssh backup-server "find $REMOTE_BACKUP/$(date +%Y%m%d)/ -name '*.bson' -exec md5sum {} \;" > /tmp/remote_checksum.txt
# S3校验
aws s3 ls $S3_BUCKET/$(date +%Y%m%d)/ --recursive > /tmp/s3_list.txt

# 5. 比较校验和
if diff /tmp/local_checksum.txt /tmp/remote_checksum.txt > /dev/null; then
    echo "✓ Local and remote backups match"
else
    echo "✗ Backup mismatch detected!"
fi

echo "3-2-1 backup strategy executed"

备份加密

#!/bin/bash
# MongoDB备份加密

# 配置
BACKUP_DIR="/backup/mongodb"
ENCRYPTED_DIR="/backup/mongodb/encrypted"
GPG_RECIPIENT="admin@example.com"

# 1. 执行备份
mongodump --out $BACKUP_DIR/$(date +%Y%m%d)

# 2. 压缩并加密
tar -czf - $BACKUP_DIR/$(date +%Y%m%d) | \
gpg --cipher-algo AES256 --compress-algo 1 --symmetric --output $ENCRYPTED_DIR/backup_$(date +%Y%m%d).tar.gz.gpg

# 3. 安全删除原始备份
shred -u -z -n 5 $BACKUP_DIR/$(date +%Y%m%d)/* 2>/dev/null || rm -rf $BACKUP_DIR/$(date +%Y%m%d)

# 4. 记录加密信息
echo "Backup encrypted: backup_$(date +%Y%m%d).tar.gz.gpg" > $ENCRYPTED_DIR/encryption_log.txt
echo "Encryption method: AES256" >> $ENCRYPTED_DIR/encryption_log.txt
echo "Created: $(date)" >> $ENCRYPTED_DIR/encryption_log.txt

# 5. 解密示例(需要时)
# gpg --decrypt $ENCRYPTED_DIR/backup_20240101.tar.gz.gpg | tar -xzf -

echo "Encrypted backup completed"

备份访问控制

#!/bin/bash
# 备份目录权限管理

BACKUP_ROOT="/backup/mongodb"

# 1. 创建专用备份用户
if ! id "mongodb-backup" &>/dev/null; then
    useradd -r -s /bin/false mongodb-backup
fi

# 2. 设置目录权限
chown -R mongodb-backup:mongodb-backup $BACKUP_ROOT
chmod 700 $BACKUP_ROOT
chmod 600 $BACKUP_ROOT/* 2>/dev/null

# 3. 设置ACL(如果需要共享访问)
setfacl -R -m u:mongodb-restore:r-x $BACKUP_ROOT
setfacl -R -m u:backup-admin:rwx $BACKUP_ROOT

# 4. 审计日志
auditctl -w $BACKUP_ROOT -p warx -k mongodb-backup-access

echo "Backup access control configured"

灾难恢复计划

恢复流程文档化

#!/bin/bash
# MongoDB灾难恢复脚本

# 配置
BACKUP_DIR="/backup/mongodb/daily"
RESTORE_HOST="localhost"
RESTORE_PORT="27017"
MONGO_USER="restoreUser"
MONGO_PASS="restorepass"

# 灾难恢复步骤
cat > /tmp/recovery_steps.txt << 'EOF'
# MongoDB灾难恢复步骤

## 1. 评估灾难情况
- 确定故障范围(单节点/副本集/分片集群)
- 确定数据丢失时间点
- 评估可用备份

## 2. 准备恢复环境
- 确保目标服务器可用
- 安装相同版本的MongoDB
- 准备足够的磁盘空间

## 3. 选择恢复策略
- 完整恢复:使用最新完整备份
- 增量恢复:完整备份 + 增量备份
- PITR恢复:恢复到特定时间点

## 4. 执行恢复
- 停止目标MongoDB服务
- 清空数据目录
- 执行恢复命令
- 启动MongoDB服务

## 5. 验证恢复
- 检查数据库完整性
- 验证关键数据
- 测试应用连接

## 6. 业务恢复
- 切换应用连接
- 监控系统状态
- 通知相关人员
EOF

# 自动化恢复脚本
restore_mongodb() {
    local backup_path=$1
    local restore_host=$2
    local restore_port=$3
    
    echo "Starting MongoDB restore from: $backup_path"
    
    # 1. 停止MongoDB(如果需要)
    # systemctl stop mongod
    
    # 2. 清空数据目录(谨慎操作!)
    # rm -rf /var/lib/mongodb/*
    
    # 3. 执行恢复
    mongorestore --host $restore_host --port $restore_port \
                 --username $MONGO_USER --password $MONGO_PASS \
                 --authenticationDatabase admin \
                 --gzip \
                 $backup_path
    
    # 4. 启动MongoDB
    # systemctl start mongod
    
    # 5. 等待启动
    sleep 10
    
    # 6. 验证
    mongo --host $restore_host --port $restore_port --eval "
        try {
            db.adminCommand({ping:1});
            print('✓ MongoDB is running and accessible');
            
            // 检查数据库列表
            var dbs = db.adminCommand('listDatabases').databases;
            print('Restored databases: ' + dbs.length);
            
            // 检查副本集状态(如果是副本集)
            var isMaster = db.isMaster();
            if (isMaster.set) {
                print('Replica set name: ' + isMaster.set);
                print('Primary: ' + isMaster.primary);
            }
        } catch (e) {
            print('✗ Error: ' + e);
            quit(1);
        }
    "
    
    echo "Restore completed successfully"
}

# 使用示例
# restore_mongodb "/backup/mongodb/daily/20240101" "localhost" "27017"

恢复测试计划

#!/bin/bash
# 定期恢复测试

# 配置
TEST_SCHEDULE="weekly"  # weekly/monthly
BACKUP_DIR="/backup/mongodb/daily"
TEST_ENVIRONMENT="staging"

# 每周执行恢复测试
if [ "$TEST_SCHEDULE" = "weekly" ]; then
    # 选择最近的备份
    LATEST_BACKUP=$(ls -td $BACKUP_DIR/*/ | head -1)
    
    # 在测试环境恢复
    echo "Starting weekly restore test..."
    echo "Backup: $LATEST_BACKUP"
    echo "Test environment: $TEST_ENVIRONMENT"
    
    # 执行恢复(使用测试配置)
    /usr/local/bin/mongodb_restore_test.sh $LATEST_BACKUP $TEST_ENVIRONMENT
    
    # 生成测试报告
    cat > /tmp/restore_test_report_$(date +%Y%m%d).txt << EOF
MongoDB Restore Test Report
Date: $(date)
Backup: $LATEST_BACKUP
Test Environment: $TEST_ENVIRONMENT
Status: COMPLETED
Duration: TBD
Issues: None
EOF
    
    echo "Weekly restore test completed"
fi

备份最佳实践总结

1. 备份策略设计原则

RTO(恢复时间目标)和RPO(恢复点目标)

  • RTO:业务可容忍的最大停机时间
  • RPO:业务可容忍的最大数据丢失量
# 根据RTO/RPO制定策略
# RTO < 1小时:需要热备、快速恢复
# RPO < 15分钟:需要增量备份、PITR

if [ $RTO -lt 3600 ]; then
    echo "需要快速恢复方案:文件系统快照或副本集备份"
fi

if [ $RPO -lt 900 ]; then
    echo "需要高频备份:每15分钟增量备份"
fi

2. 备份频率建议

数据重要性 全量备份 增量备份 保留周期
关键业务 每天 每小时 90天
重要业务 每周 每天 30天
一般业务 每周 每周 7天
开发测试 每月 - 3天

3. 备份监控指标

# 关键监控指标
BACKUP_METRICS=(
    "backup_success_rate"      # 备份成功率
    "backup_duration"          # 备份耗时
    "backup_size"              # 备份大小
    "restore_test_success"     # 恢复测试成功率
    "backup_age"               # 最新备份时间
    "storage_utilization"      # 存储使用率
)

# 监控脚本示例
monitor_backup_metrics() {
    local metric=$1
    
    case $metric in
        "backup_success_rate")
            # 计算最近30天成功率
            total=$(grep -c "Backup completed" /var/log/mongodb_backup.log 2>/dev/null || echo 0)
            failed=$(grep -c "Backup failed" /var/log/mongodb_backup.log 2>/dev/null || echo 0)
            if [ $total -gt 0 ]; then
                rate=$((100 * (total - failed) / total))
                echo "Backup success rate: $rate%"
            fi
            ;;
        "backup_duration")
            # 获取平均备份时间
            avg_time=$(grep "Backup completed" /var/log/mongodb_backup.log | awk '{print $NF}' | sort -n | awk '{sum+=$1; count++} END {if(count>0) print sum/count; else print 0}')
            echo "Average backup duration: ${avg_time}s"
            ;;
    esac
}

4. 常见陷阱与避免方法

  1. 忘记测试恢复:定期进行恢复测试
  2. 备份未加密:敏感数据必须加密
  3. 单点备份:遵循3-2-1法则
  4. 无监控告警:建立完善的监控体系
  5. 权限过宽:最小权限原则
  6. 忽略版本兼容性:备份时记录MongoDB版本

5. 备份策略检查清单

#!/bin/bash
# 备份策略检查清单

checklist=(
    "✓ 定期全量备份已配置"
    "✓ 增量备份已启用"
    "✓ 备份已加密"
    "✓ 备份已监控"
    "✓ 恢复测试已执行"
    "✓ 异地备份已配置"
    "✓ 备份保留策略已定义"
    "✓ 备份文档已更新"
    "✓ 团队已培训"
    "✓ 应急预案已准备"
)

echo "MongoDB Backup Strategy Checklist"
echo "================================="
for item in "${checklist[@]}"; do
    echo "$item"
done

# 自动化检查
echo ""
echo "Automated Checks:"
echo "-----------------"

# 检查最近备份
if find /backup/mongodb -name "*.bson" -mtime -1 | grep -q .; then
    echo "✓ Recent backup exists"
else
    echo "✗ No recent backup found"
fi

# 检查备份日志
if grep -q "Backup completed" /var/log/mongodb_backup.log 2>/dev/null; then
    echo "✓ Backup logging configured"
else
    echo "✗ Backup logging not found"
fi

# 检查恢复测试
if [ -f /tmp/restore_test_report_*.txt ]; then
    echo "✓ Recovery tests performed"
else
    echo "✗ No recovery test records"
fi

结论

MongoDB备份策略是确保数据安全和业务连续性的基石。通过本文的详细解析,您应该已经掌握了从基础到高级的备份方法,包括:

  1. 基础工具:mongodump/mongorestore的熟练使用
  2. 高级策略:副本集备份、分片集群备份、增量备份和PITR
  3. 自动化:脚本编写、定时任务、监控告警
  4. 安全管理:加密、权限控制、合规性
  5. 灾难恢复:恢复流程、测试计划、应急预案

记住,备份不是一次性工作,而是一个持续的过程。最好的备份策略是那个经过测试、监控且团队熟悉的策略。定期审查和更新您的备份计划,确保它始终与业务需求保持同步。

最后,永远记住:没有经过测试的备份等于没有备份。从今天开始,制定您的MongoDB备份策略,并确保定期测试恢复流程。您的数据值得这样的保护。