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

在现代应用架构中,MongoDB作为领先的NoSQL数据库,承载着大量关键业务数据。然而,数据丢失的风险始终存在——从硬件故障、人为误操作到恶意攻击,都可能在瞬间摧毁宝贵的数据资产。根据行业统计,超过60%的企业在遭遇数据丢失后会在一年内倒闭,而拥有完善备份策略的公司能够将恢复时间缩短90%以上。

本文将深入探讨MongoDB备份的核心策略,从理论基础到实战操作,帮助您构建坚不可摧的数据保护体系。我们将涵盖备份类型的选择、自动化方案的实施、恢复流程的优化,以及如何在云原生环境中实现最佳实践。

MongoDB备份基础概念

为什么传统备份方法不适用

MongoDB的架构特性决定了其备份方式与传统关系型数据库有显著差异。MongoDB使用文档模型和内存映射文件,这使得简单的文件复制无法保证数据一致性。在备份过程中,必须考虑以下几个关键因素:

  1. WiredTiger存储引擎的事务特性:MongoDB 3.2+默认使用WiredTiger,它支持文档级并发控制和压缩,备份时需要确保所有写入操作被正确持久化
  2. 复制集架构的复杂性:主节点和从节点之间的同步机制要求备份必须考虑oplog(操作日志)的连续性
  3. 分片集群的数据分布:数据分布在多个分片上,备份需要协调所有分片的状态

MongoDB备份的核心原则

成功的MongoDB备份策略必须遵循以下原则:

  • 原子性:备份必须捕获某个时间点的完整一致状态
  • 完整性:所有数据、索引和配置信息都必须被包含
  • 可恢复性:备份必须能够在合理时间内恢复到生产环境
  • 最小化RPO:恢复点目标(RPO)应尽可能接近零,确保丢失数据最少

备份类型详解

1. 物理备份 vs 逻辑备份

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

物理备份直接复制MongoDB的数据文件,速度快但对存储引擎和文件系统有特定要求。

适用场景

  • 大数据量(TB级别)的备份
  • 对备份时间窗口要求严格的环境
  • 使用支持快照的文件系统(如LVM、ZFS、云存储快照)

实战示例:使用LVM快照进行物理备份

#!/bin/bash
# MongoDB LVM物理备份脚本

# 配置参数
MONGO_DATA="/var/lib/mongodb"
MONGO_LOCK="/var/lib/mongodb/mongod.lock"
BACKUP_DIR="/backup/mongodb"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/mongodb_backup.log"

# 检查MongoDB是否运行
if [ ! -f "$MONGO_LOCK" ]; then
    echo "$(date): MongoDB is not running, backup aborted" >> $LOG_FILE
    exit 1
fi

# 创建LVM快照(假设数据在/dev/mongo_vg/mongo_lv卷上)
echo "$(date): Creating LVM snapshot..." >> $LOG_FILE
lvcreate -L 10G -s -n mongo_snap /dev/mongo_vg/mongo_lv

if [ $? -ne 0 ]; then
    echo "$(date): Failed to create LVM snapshot" >> $LOG_FILE
    exit 1
fi

# 挂载快照
mkdir -p /mnt/mongo_snapshot
mount /dev/mongo_vg/mongo_snap /mnt/mongo_snapshot

# 复制数据文件(排除临时文件)
echo "$(date): Starting data copy..." >> $LOG_FILE
rsync -av --exclude='*.sock' --exclude='*.lock' /mnt/mongo_snapshot/ $BACKUP_DIR/$DATE/

# 卸载并删除快照
umount /mnt/mongo_snapshot
lvremove -f /dev/mongo_vg/mongo_snap

# 压缩备份
echo "$(date): Compressing backup..." >> $LOG_FILE
tar -czf $BACKUP_DIR/$DATE.tar.gz -C $BACKUP_DIR $DATE
rm -rf $BACKUP_DIR/$DATE

# 清理旧备份(保留最近7天)
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete

echo "$(date): Backup completed successfully: $BACKUP_DIR/$DATE.tar.gz" >> $LOG_FILE

逻辑备份(mongodump/mongorestore)

逻辑备份通过导出BSON格式的数据实现,兼容性好但速度较慢。

适用场景

  • 跨版本恢复需求
  • 需要选择性备份特定数据库或集合
  • 小到中等数据量(GB级别)
  • 需要数据迁移或格式转换

实战示例:使用mongodump进行逻辑备份

#!/bin/bash
# MongoDB逻辑备份脚本

# 配置参数
MONGO_HOST="localhost"
MONGO_PORT="27017"
MONGO_USER="backup_user"
MONGO_PASS="backup_password"
BACKUP_DIR="/backup/mongodb/logical"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/mongodb_logical_backup.log"

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

# 执行备份(带认证)
echo "$(date): Starting mongodump..." >> $LOG_FILE
mongodump --host $MONGO_HOST --port $MONGO_PORT \
          --username $MONGO_USER --password $MONGO_PASS \
          --authenticationDatabase admin \
          --out $BACKUP_DIR/$DATE \
          --gzip \
          --oplog

# 检查备份结果
if [ $? -eq 0 ]; then
    # 创建备份信息文件
    cat > $BACKUP_DIR/$DATE/backup.info << EOF
Backup Date: $(date)
MongoDB Version: $(mongod --version | head -1)
Data Size: $(du -sh $BACKUP_DIR/$DATE | cut -f1)
EOF
    
    # 压缩整个备份目录
    tar -czf $BACKUP_DIR/$DATE.tar.gz -C $BACKUP_DIR $DATE
    rm -rf $BACKUP_DIR/$DATE
    
    # 清理旧备份(保留最近3天)
    find $BACKUP_DIR -name "*.tar.gz" -mtime +3 -delete
    
    echo "$(date): Backup completed: $BACKUP_DIR/$DATE.tar.gz" >> $LOG_FILE
else
    echo "$(date): Backup failed!" >> $LOG_FILE
    exit 1
fi

2. 增量备份 vs 全量备份

增量备份策略

增量备份只捕获自上次备份以来的变化,大幅减少存储空间和备份时间。

实现方式

  • Oplog重放:利用MongoDB复制集的oplog实现增量备份
  • 文件系统增量:使用rsync或类似工具进行增量同步
  • 应用层增量:在应用中实现变更追踪

实战示例:基于Oplog的增量备份

#!/usr/bin/env python3
# MongoDB增量备份脚本(基于Oplog)

import pymongo
import json
import os
from datetime import datetime, timedelta

class MongoDBIncrementalBackup:
    def __init__(self, uri, backup_dir):
        self.client = pymongo.MongoClient(uri)
        self.db = self.client.admin
        self.backup_dir = backup_dir
        self.last_backup_file = os.path.join(backup_dir, "last_backup.txt")
        
    def get_last_backup_ts(self):
        """获取上次备份的时间戳"""
        if os.path.exists(self.last_backup_file):
            with open(self.last_backup_file, 'r') as f:
                return json.load(f)
        return None
    
    def save_current_ts(self, ts):
        """保存当前备份时间戳"""
        with open(self.last_backup_file, 'w') as f:
            json.dump(ts, f)
    
    def perform_incremental_backup(self):
        """执行增量备份"""
        last_ts = self.get_last_backup_ts()
        
        # 查询oplog
        oplog = self.db.oplog.rs
        
        if last_ts:
            query = {"ts": {"$gt": pymongo.Timestamp(last_ts['t'], last_ts['i'])}}
        else:
            query = {}
        
        # 获取oplog条目
        ops = list(oplog.find(query).sort("ts", 1))
        
        if not ops:
            print("No new operations to backup")
            return
        
        # 保存增量数据
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_file = os.path.join(self.backup_dir, f"inc_{timestamp}.json")
        
        with open(backup_file, 'w') as f:
            for op in ops:
                f.write(json.dumps(op) + "\n")
        
        # 更新最后时间戳
        last_op = ops[-1]
        ts = last_op['ts']
        self.save_current_ts({"t": ts.time, "i": ts.inc})
        
        print(f"Backed up {len(ops)} operations to {backup_file}")

# 使用示例
if __name__ == "__main__":
    backup = MongoDBIncrementalBackup(
        "mongodb://backup_user:pass@localhost:27017/admin",
        "/backup/mongodb/incremental"
    )
    backup.perform_incremental_backup()

自动化备份方案

1. Cron定时任务

使用Linux的cron服务实现定时备份是最基础但有效的方法。

实战配置

# 编辑crontab: crontab -e

# 每天凌晨2点执行全量备份
0 2 * * * /opt/mongodb/scripts/full_backup.sh >> /var/log/mongodb_backup.log 2>&1

# 每4小时执行一次增量备份
0 */4 * * * /opt/mongodb/scripts/incremental_backup.sh >> /var/log/mongodb_incremental.log 2>&1

# 每周日进行一次备份验证(恢复测试)
0 3 * * 0 /opt/mongodb/scripts/verify_backup.sh >> /var/log/mongodb_verify.log 2>&1

# 每月1号清理超过30天的旧备份
0 1 1 * * find /backup/mongodb -name "*.tar.gz" -mtime +30 -delete

2. 使用MongoDB Atlas备份服务

MongoDB Atlas提供的托管备份服务具有以下优势:

  • 零配置:自动配置和管理备份
  • 时间点恢复(PITR):可恢复到任意秒级时间点
  • 全球分布式:跨区域备份确保高可用性
  1. 自动化备份方案

1. Cron定时任务

使用Linux的cron服务实现定时备份是最基础但有效的方法。

实战配置

# 编辑crontab: crontab -e

# 每天凌晨2点执行全量备份
0 2 * * * /opt/mongodb/scripts/full_backup.sh >> /var/log/mongodb_backup.log 2>&1

# 每4小时执行一次增量备份
0 */4 * * * /opt/mongodb/scripts/incremental_backup.sh >> /var/log/mongodb_incremental.log 2>&1

# 每周日进行一次备份验证(恢复测试)
0 3 * * 0 /opt/mongodb/scripts/verify_backup.sh >> /var/log/mongodb_verify.log 2>&1

# 每月1号清理超过30天的旧备份
0 1 1 * * find /backup/mongodb -name "*.tar.gz" -mtime +30 -delete

2. 使用MongoDB Atlas备份服务

MongoDB Atlas提供的托管备份服务具有以下优势:

  • 零配置:自动配置和管理备份
  • 时间点恢复(PITR):可恢复到任意秒级时间点
  • 全球分布式:跨区域备份确保高可用性
  • 增量备份:自动增量备份,节省存储空间

Atlas备份配置示例

// 在Atlas UI中配置或通过API
{
  "snapshotIntervalHours": 6,
  "snapshotRetentionDays": 7,
  "pointInTimeRestoreEnabled": true,
  "copyRegion": ["us-east-1", "us-west-2"]
}

3. 使用Kubernetes CronJob实现容器化备份

在Kubernetes环境中,可以使用CronJob来管理备份任务。

Kubernetes CronJob YAML配置

apiVersion: batch/v1
kind: CronJob
metadata:
  name: mongodb-backup
spec:
  schedule: "0 2 * * *"  # 每天凌晨2点
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: mongo:6.0
            command:
            - /bin/bash
            - -c
            - |
              #!/bin/bash
              DATE=$(date +%Y%m%d_%H%M%S)
              BACKUP_DIR="/backup/mongodb"
              
              # 执行备份
              mongodump --host mongodb://$MONGO_USER:$MONGO_PASS@mongodb:27017/admin \
                        --out $BACKUP_DIR/$DATE \
                        --gzip \
                        --oplog
              
              # 上传到S3
              aws s3 cp $BACKUP_DIR/$DATE s3://my-backup-bucket/mongodb/$DATE/ --recursive
              
              # 清理本地文件
              rm -rf $BACKUP_DIR/$DATE
            env:
            - name: MONGO_USER
              valueFrom:
                secretKeyRef:
                  name: mongodb-secret
                  key: username
            - name: MONGO_PASS
              valueFrom:
                secretKeyRef:
                  name: mongodb-secret
                  key: password
            volumeMounts:
            - name: backup-storage
              mountPath: /backup
          restartPolicy: OnFailure
          volumes:
          - name: backup-storage
            persistentVolumeClaim:
              claimName: backup-pvc

备份存储与管理

1. 3-2-1备份原则

3-2-1原则:至少3份数据副本,存储在2种不同介质上,其中1份存放在异地。

实现方案

  • 本地存储:快速恢复,保留最近7天
  • 异地存储:灾难恢复,保留30天
  • 云存储:长期归档,保留1年

2. 云存储集成

AWS S3存储示例

#!/bin/bash
# 上传备份到S3并设置生命周期

BACKUP_FILE="/backup/mongodb/full_20240101.tar.gz"
S3_BUCKET="s3://my-mongodb-backups/full/"

# 上传到S3
aws s3 cp $BACKUP_FILE $S3_BUCKET

# 设置S3生命周期策略(通过AWS CLI)
aws s3api put-bucket-lifecycle-configuration \
    --bucket my-mongodb-backups \
    --lifecycle-configuration '{
        "Rules": [
            {
                "ID": "FullBackupLifecycle",
                "Status": "Enabled",
                "Filter": {
                    "Prefix": "full/"
                },
                "Transitions": [
                    {
                        "Days": 30,
                        "StorageClass": "STANDARD_IA"
                    },
                    {
                        "Days": 90,
                        "StorageClass": "GLACIER"
                    }
                ],
                "Expiration": {
                    "Days": 365
                }
            }
        ]
    }'

Azure Blob存储示例

#!/usr/bin/env python3
# 上传备份到Azure Blob存储

from azure.storage.blob import BlobServiceClient
import os

def upload_to_azure(backup_file, container_name):
    """上传备份文件到Azure Blob存储"""
    
    # 连接字符串(从Azure门户获取)
    connect_str = os.getenv("AZURE_STORAGE_CONNECTION_STRING")
    
    # 创建BlobServiceClient
    blob_service_client = BlobServiceClient.from_connection_string(connect_str)
    
    # 创建容器(如果不存在)
    container_client = blob_service_client.get_container_client(container_name)
    if not container_client.exists():
        container_client.create_container()
    
    # 上传文件
    blob_name = os.path.basename(backup_file)
    blob_client = container_client.get_blob_client(blob_name)
    
    with open(backup_file, "rb") as data:
        blob_client.upload_blob(data, overwrite=True)
    
    print(f"Uploaded {backup_file} to Azure Blob Storage")

# 使用示例
upload_to_azure("/backup/mongodb/full_20240101.tar.gz", "mongodb-backups")

3. 备份加密

使用GPG加密备份

#!/bin/bash
# 加密备份文件

BACKUP_FILE="/backup/mongodb/full_20240101.tar.gz"
ENCRYPTED_FILE="${BACKUP_FILE}.gpg"
GPG_KEY="backup-key@company.com"

# 加密文件
gpg --encrypt --recipient $GPG_KEY --output $ENCRYPTED_FILE $BACKUP_FILE

# 验证加密
gpg --verify $ENCRYPTED_FILE

# 删除原始文件(可选)
# rm $BACKUP_FILE

echo "Backup encrypted: $ENCRYPTED_FILE"

恢复策略与实战

1. 全量恢复

使用mongorestore恢复全量备份

#!/bin/bash
# MongoDB全量恢复脚本

# 配置参数
BACKUP_FILE="/backup/mongodb/full_20240101.tar.gz"
RESTORE_DIR="/tmp/mongodb_restore"
MONGO_URI="mongodb://admin:password@localhost:27017/admin"
LOG_FILE="/var/log/mongodb_restore.log"

# 检查备份文件
if [ ! -f "$BACKUP_FILE" ]; then
    echo "$(date): Backup file not found: $BACKUP_FILE" >> $LOG_FILE
    exit 1
fi

# 创建恢复目录
mkdir -p $RESTORE_DIR

# 解压备份
echo "$(date): Extracting backup..." >> $LOG_FILE
tar -xzf $BACKUP_FILE -C $RESTORE_DIR

# 停止MongoDB服务(确保数据一致性)
echo "$(date): Stopping MongoDB..." >> $LOG_FILE
systemctl stop mongod

# 清空现有数据(危险操作,需谨慎)
echo "$(date): Clearing existing data..." >> $LOG_FILE
rm -rf /var/lib/mongodb/*

# 执行恢复
echo "$(date): Starting mongorestore..." >> $LOG_FILE
mongorestore --uri $MONGO_URI \
             --dir $RESTORE_DIR/ \
             --gzip \
             --drop \
             --oplogReplay

# 检查恢复结果
if [ $? -eq 0 ]; then
    echo "$(date): Restore completed successfully" >> $LOG_FILE
    
    # 启动MongoDB
    systemctl start mongod
    
    # 验证数据
    mongo $MONGO_URI --eval "db.adminCommand({listDatabases:1})"
else
    echo "$(date): Restore failed!" >> $LOG_FILE
    exit 1
fi

# 清理临时文件
rm -rf $RESTORE_DIR

2. 时间点恢复(PITR)

使用Oplog进行时间点恢复

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

# 配置参数
BACKUP_DIR="/backup/mongodb/full_20240101"
OPLOG_FILE="/backup/mongodb/oplog.bson"
RESTORE_TIMESTAMP="2024-01-01T14:30:00Z"
MONGO_URI="mongodb://admin:password@localhost:27017/admin"

# 1. 恢复全量备份
mongorestore --uri $MONGO_URI \
             --dir $BACKUP_DIR \
             --gzip \
             --drop

# 2. 重放到指定时间点
mongorestore --uri $MONGO_URI \
             --oplogLimit $RESTORE_TIMESTAMP \
             --oplogReplay \
             --dir $BACKUP_DIR

echo "Time point restore completed to: $RESTORE_TIMESTAMP"

3. 选择性恢复

恢复特定数据库或集合

# 恢复单个数据库
mongorestore --uri $MONGO_URI \
             --db myapp \
             --gzip \
             /backup/mongodb/full_20240101/myapp

# 恢复单个集合
mongorestore --uri $MONGO_URI \
             --db myapp \
             --collection users \
             --gzip \
             /backup/mongodb/full_20240101/myapp/users.bson

# 恢复时重命名数据库
mongorestore --uri $MONGO_URI \
             --nsFrom "myapp.*" \
             --nsTo "myapp_restore.*" \
             --gzip \
             /backup/mongodb/full_20240101/myapp

高级备份策略

1. 分片集群备份

分片集群备份需要协调所有分片

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

# 配置参数
CONFIG_SERVER="config1.example.com:27019"
SHARD1="shard1.example.com:27018"
SHARD2="shard2.example.com:27018"
MONGOS="mongos.example.com:27017"
BACKUP_DIR="/backup/mongodb/sharded_cluster"
DATE=$(date +%Y%m%d_%H%M%S)

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

# 1. 备份配置服务器
echo "Backing up config servers..."
mongodump --host $CONFIG_SERVER \
          --out $BACKUP_DIR/$DATE/config \
          --gzip

# 2. 备份每个分片
echo "Backing up shard1..."
mongodump --host $SHARD1 \
          --out $BACKUP_DIR/$DATE/shard1 \
          --gzip

echo "Backing up shard2..."
mongodump --host $SHARD2 \
          --out $BACKUP_DIR/$DATE/shard2 \
          --gzip

# 3. 备份元数据(通过mongos)
echo "Backing up metadata..."
mongodump --host $MONGOS \
          --db config \
          --out $BACKUP_DIR/$DATE/metadata \
          --gzip

# 4. 创建备份清单
cat > $BACKUP_DIR/$DATE/backup_manifest.json << EOF
{
  "timestamp": "$(date -Iseconds)",
  "config_server": "$CONFIG_SERVER",
  "shards": ["$SHARD1", "$SHARD2"],
  "mongos": "$MONGOS",
  "backup_location": "$BACKUP_DIR/$DATE"
}
EOF

echo "Sharded cluster backup completed: $BACKUP_DIR/$DATE"

2. 增量备份与恢复

基于Oplog的增量备份

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

# 配置参数
MONGO_URI="mongodb://backup_user:pass@localhost:27017/admin"
BACKUP_DIR="/backup/mongodb/incremental"
LAST_BACKUP_FILE="$BACKUP_DIR/last_backup.txt"
DATE=$(date +%Y%m%d_%H%M%S)

# 获取上次备份的Oplog时间戳
if [ -f "$LAST_BACKUP_FILE" ]; then
    LAST_TS=$(cat $LAST_BACKUP_FILE)
    QUERY="ts: {\$gt: Timestamp($LAST_TS)}"
else
    QUERY=""
fi

# 执行增量备份
mongodump --uri $MONGO_URI \
          --db local \
          --collection oplog.rs \
          --query "$QUERY" \
          --out $BACKUP_DIR/$DATE \
          --gzip

# 保存本次备份的时间戳
CURRENT_TS=$(mongo $MONGO_URI --quiet --eval "db.oplog.rs.find().sort({\$natural:-1}).limit(1).next().ts")
echo $CURRENT_TS > $LAST_BACKUP_FILE

echo "Incremental backup completed: $BACKUP_DIR/$DATE"

3. 备份验证与监控

备份验证脚本

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

# 配置参数
BACKUP_FILE="/backup/mongodb/full_20240101.tar.gz"
TEST_DIR="/tmp/backup_verify"
MONGO_TEST_URI="mongodb://test:test@localhost:27017/verify_db"

# 创建测试目录
mkdir -p $TEST_DIR

# 解压备份
tar -xzf $BACKUP_FILE -C $TEST_DIR

# 尝试恢复到测试数据库
mongorestore --uri $MONGO_TEST_URI \
             --dir $TEST_DIR/ \
             --gzip \
             --drop

# 验证数据完整性
if [ $? -eq 0 ]; then
    # 检查文档数量
    DOC_COUNT=$(mongo $MONGO_TEST_URI --quiet --eval "db.users.count()")
    
    # 检查索引
    INDEX_COUNT=$(mongo $MONGO_TEST_URI --quiet --eval "db.users.getIndexes().length")
    
    echo "Backup verification successful!"
    echo "Document count: $DOC_COUNT"
    echo "Index count: $INDEX_COUNT"
    
    # 清理测试数据库
    mongo $MONGO_TEST_URI --eval "db.dropDatabase()"
else
    echo "Backup verification failed!"
    exit 1
fi

# 清理临时文件
rm -rf $TEST_DIR

监控与告警

1. 备份状态监控

使用MongoDB Atlas监控

// Atlas API监控备份状态
const axios = require('axios');

async function checkBackupStatus() {
    const url = 'https://cloud.mongodb.com/api/atlas/v1.0/groups/{groupId}/clusters/{clusterName}/backup/snapshots';
    
    const response = await axios.get(url, {
        auth: {
            username: 'publicKey',
            password: 'privateKey'
        }
    });
    
    const snapshots = response.data.results;
    const latestSnapshot = snapshots[0];
    
    if (latestSnapshot.status !== 'completed') {
        console.error(`Backup failed: ${latestSnapshot.status}`);
        // 发送告警
        sendAlert(`MongoDB backup failed: ${latestSnapshot.status}`);
    } else {
        console.log(`Backup successful: ${latestSnapshot.id}`);
    }
}

自定义监控脚本

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

# 配置参数
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): No backup files found!" >> $LOG_FILE
    echo "MongoDB backup missing!" | mail -s "Backup Alert" $ALERT_EMAIL
    exit 1
fi

# 检查备份文件大小(最小100MB)
BACKUP_SIZE=$(stat -c%s "$LATEST_BACKUP")
MIN_SIZE=$((100 * 1024 * 1024))

if [ $BACKUP_SIZE -lt $MIN_SIZE ]; then
    echo "$(date): Backup file too small: $LATEST_BACKUP" >> $LOG_FILE
    echo "MongoDB backup file too small!" | mail -s "Backup Alert" $ALERT_EMAIL
    exit 1
fi

# 检查备份文件修改时间(最近24小时内)
CURRENT_TIME=$(date +%s)
BACKUP_TIME=$(stat -c%Y "$LATEST_BACKUP")
DIFF_TIME=$((CURRENT_TIME - BACKUP_TIME))

if [ $DIFF_TIME -gt 86400 ]; then
    echo "$(date): Backup file too old: $LATEST_BACKUP" >> $LOG_FILE
    echo "MongoDB backup is stale!" | mail -s "Backup Alert" $ALERT_EMAIL
    exit 1
fi

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

云原生环境下的备份

1. AWS环境下的MongoDB备份

使用AWS Backup服务

{
  "BackupPlan": {
    "BackupPlanName": "MongoDB-Backup-Plan",
    "Rules": [
      {
        "RuleName": "DailyMongoDBBackup",
        "TargetBackupVaultName": "MongoDB-Vault",
        "ScheduleExpression": "cron(0 2 * * ? *)",
        "StartWindowMinutes": 60,
        "CompletionWindowMinutes": 180,
        "Lifecycle": {
          "DeleteAfterDays": 30
        },
        "RecoveryPointTags": {
          "Environment": "Production",
          "Database": "MongoDB"
        }
      }
    ]
  }
}

使用EBS快照

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

# 获取MongoDB实例的EBS卷ID
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
VOLUME_ID=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \
              --query 'Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId' \
              --output text)

# 创建快照
SNAPSHOT_ID=$(aws ec2 create-snapshot \
                --volume-id $VOLUME_ID \
                --description "MongoDB Backup $(date +%Y-%m-%d)" \
                --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Backup,Value=MongoDB}]' \
                --query SnapshotId \
                --output text)

echo "Created snapshot: $SNAPSHOT_ID"

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

# 保留最近7个快照,删除旧的
SNAPSHOTS=$(aws ec2 describe-snapshots \
              --filters "Name=tag:Backup,Values=MongoDB" \
              --query 'Snapshots[*].SnapshotId' \
              --output text | tr '\t' '\n' | sort)

SNAPSHOT_COUNT=$(echo $SNAPSHOTS | wc -w)

if [ $SNAPSHOT_COUNT -gt 7 ]; then
    OLD_SNAPSHOTS=$(echo $SNAPSHOTS | head -n $(($SNAPSHOT_COUNT - 7)))
    for snap in $OLD_SNAPSHOTS; do
        aws ec2 delete-snapshot --snapshot-id $snap
        echo "Deleted old snapshot: $snap"
    done
fi

2. Kubernetes环境下的MongoDB备份

使用Kubernetes Volume Snapshots

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: mongodb-snapshot
  namespace: mongodb
spec:
  volumeSnapshotClassName: csi-snapclass
  source:
    persistentVolumeClaimName: mongodb-data-pvc

使用Stash进行Kubernetes应用备份

apiVersion: stash.appscode.com/v1beta1
kind: BackupConfiguration
metadata:
  name: mongodb-backup
  namespace: mongodb
spec:
  schedule: "0 2 * * *"
  target:
    ref:
      apiVersion: apps/v1
      kind: Deployment
      name: mongodb
    volumeMounts:
    - name: data
      mountPath: /data/db
    paths:
    - /data/db
  task:
    name: mongodb-backup
  repository:
    name: s3-repo
  retentionPolicy:
    name: keep-monthly
    keepDaily: 7
    keepWeekly: 4
    keepMonthly: 12

备份最佳实践总结

1. 备份策略制定

RPO和RTO定义

  • RPO(恢复点目标):可接受的数据丢失量,决定备份频率
  • RTO(恢复时间目标):恢复业务所需时间,决定恢复流程复杂度

推荐策略

  • 生产环境:每4小时增量备份,每天全量备份
  • 开发环境:每天全量备份
  • 关键业务:实时增量备份 + 每小时全量备份

2. 备份测试计划

每月执行一次恢复演练

#!/bin/bash
# 月度恢复演练脚本

# 选择随机备份文件
BACKUP_FILES=(/backup/mongodb/*.tar.gz)
RANDOM_BACKUP=${BACKUP_FILES[$RANDOM % ${#BACKUP_FILES[@]}]}

# 在隔离环境恢复
docker run -d --name mongodb-test -p 27018:27017 mongo:6.0

# 等待MongoDB启动
sleep 10

# 恢复数据
docker exec mongodb-test mongorestore --uri mongodb://localhost:27017 \
              --gzip \
              --dir /backup/$(basename $RANDOM_BACKUP .tar.gz)

# 运行数据完整性检查
docker exec mongodb-test mongo localhost:27017 --eval "
    db.adminCommand({listDatabases:1}).databases.forEach(function(db) {
        print('Database: ' + db.name + ' Size: ' + db.sizeOnDisk);
    });
"

# 清理
docker stop mongodb-test
docker rm mongodb-test

echo "Monthly restore drill completed: $RANDOM_BACKUP"

3. 文档与培训

备份文档应包含

  • 备份架构图
  • 恢复流程步骤
  • 联系人列表
  • 故障排查指南

定期培训

  • 每季度进行一次备份恢复演练
  • 新员工入职备份流程培训
  • 应急响应演练

结论

MongoDB备份策略是数据安全的基石。通过结合物理备份、逻辑备份、增量备份和云原生方案,您可以构建多层次的数据保护体系。记住,备份的价值只有在恢复时才能体现,因此定期测试和演练至关重要。

关键要点

  1. 多样化:不要依赖单一备份方法
  2. 自动化:减少人为错误
  3. 监控:及时发现问题
  4. 测试:确保备份可恢复
  5. 文档化:标准化操作流程

通过实施本文介绍的策略和工具,您将能够有效避免数据丢失风险,确保业务连续性,并在灾难发生时快速恢复。数据安全是一场持续的战斗,保持警惕和持续改进是成功的关键。