数据库运维8 min read

数据库备份恢复策略全解:从理论到自动化实践

数据库备份恢复策略全解:从理论到自动化实践

前言

"备份不做,删库跑路"——这虽然是玩笑话,但备份的重要性怎么强调都不过分。一套完善的备份恢复策略,是数据库运维的生命线。本文将涵盖MySQL、PostgreSQL、Redis的备份恢复方案,帮助企业建立可靠的数据库容灾体系。

一、备份策略基础

1.1 备份类型

维度 类型 说明
备份方式 物理备份 直接复制数据文件,速度快
逻辑备份 导出SQL语句,可读性好
备份范围 全量备份 备份全部数据
增量备份 只备份变化的数据
服务状态 热备份 不影响业务读写
温备份 可读不可写
冷备份 需停止服务

1.2 RPO与RTO

RPO (Recovery Point Objective) - 恢复点目标
  能容忍的最大数据丢失量
  
RTO (Recovery Time Objective) - 恢复时间目标
  从故障到恢复的最大允许时间

示例:
  核心交易系统: RPO=0, RTO<5分钟 → 需要实时同步+自动故障切换
  报表系统:     RPO=1小时, RTO<4小时 → 每小时备份即可
  日志分析:     RPO=1天, RTO<24小时 → 每天备份

1.3 备份策略矩阵

        ┌──────────────────────────────┐
        │       每日全量备份           │ ← crontab: 凌晨2点
        └──────────┬───────────────────┘
                   │
        ┌──────────▼───────────────────┐
        │     每小时增量/差异备份      │ ← crontab: 每小时
        └──────────┬───────────────────┘
                   │
        ┌──────────▼───────────────────┐
        │     WAL/Redo 实时归档        │ ← archive_command
        └──────────────────────────────┘

二、MySQL备份恢复

2.1 mysqldump 逻辑备份

#!/bin/bash
# mysql_backup.sh

BACKUP_DIR="/data/backup/mysql"
MYSQL_USER="backup"
MYSQL_PASS="password"
DB_LIST="mydb,appdb,logdb"
DATE=$(date +%Y%m%d_%H%M%S)

# 全量备份
mysqldump -u"$MYSQL_USER" -p"$MYSQL_PASS" \
    --single-transaction \          # 一致性快照
    --routines \                    # 存储过程和函数
    --triggers \                    # 触发器
    --events \                      # 事件调度
    --databases $DB_LIST \
    | gzip > "${BACKUP_DIR}/full_${DATE}.sql.gz"

# 只备份结构(不含数据)
mysqldump -u"$MYSQL_USER" -p"$MYSQL_PASS" \
    --no-data \
    --databases $DB_LIST \
    > "${BACKUP_DIR}/schema_${DATE}.sql"

2.2 XtraBackup 物理热备份

# 安装
yum install percona-xtrabackup-80 -y

# 全量备份
xtrabackup --backup \
    --target-dir=/data/backup/mysql/full \
    --user=backup --password=password \
    --compress

# 增量备份(基于上次全量或增量)
xtrabackup --backup \
    --target-dir=/data/backup/mysql/incr1 \
    --incremental-basedir=/data/backup/mysql/full \
    --user=backup --password=password \
    --compress

# 准备备份(应用日志)
xtrabackup --prepare --apply-log-only \
    --target-dir=/data/backup/mysql/full

xtrabackup --prepare \
    --target-dir=/data/backup/mysql/full \
    --incremental-dir=/data/backup/mysql/incr1

# 恢复
xtrabackup --copy-back --target-dir=/data/backup/mysql/full
chown -R mysql:mysql /var/lib/mysql

2.3 恢复验证

# 在测试环境验证备份
# 1. 启动临时MySQL
mysqld --datadir=/tmp/test_mysql --port=3307 --socket=/tmp/mysql_test.sock &

# 2. 恢复备份
mysql -S /tmp/mysql_test.sock < backup.sql

# 3. 校验数据
mysql -S /tmp/mysql_test.sock -e "
    SELECT COUNT(*) FROM mydb.orders;
    SELECT MAX(id) FROM mydb.users;
    CHECKSUM TABLE mydb.orders;
"

三、PostgreSQL备份恢复

3.1 pg_dump 逻辑备份

# 单库备份
pg_dump -h localhost -U postgres \
    -Fc \                    # 自定义压缩格式
    -f /data/backup/pg/mydb_${DATE}.dump \
    mydb

# 全库备份
pg_dumpall -h localhost -U postgres \
    --globals-only \         # 只备份全局对象(角色、表空间)
    -f /data/backup/pg/globals_${DATE}.sql

3.2 pg_basebackup 物理备份

# 全量备份
pg_basebackup -h localhost -U repl_user \
    -D /data/backup/pg/base_${DATE} \
    -Fp -Xs -P -R

# 恢复
# 1. 停止PostgreSQL
systemctl stop postgresql
# 2. 清空数据目录
rm -rf /var/lib/pgsql/14/data/*
# 3. 复制备份
cp -r /data/backup/pg/base_${DATE}/* /var/lib/pgsql/14/data/
# 4. 恢复配置
# 删除 standby.signal (如果是恢复到新主库)
# 配置 postgresql.conf
# 5. 启动
systemctl start postgresql

3.3 PITR 时间点恢复

# 恢复到特定时间点
# recovery.conf / recovery.signal (PG12+)
restore_command = 'cp /data/pg_archive/%f %p'
recovery_target_time = '2025-06-12 10:30:00'
recovery_target_action = 'promote'

# 启动后自动恢复到指定时间点

四、Redis备份

4.1 RDB自动备份

#!/bin/bash
# redis_backup.sh

REDIS_DIR="/var/lib/redis"
BACKUP_DIR="/data/backup/redis"

# 触发BGSAVE
redis-cli BGSAVE

# 等待完成
TIMEOUT=300
ELAPSED=0
while [ $ELAPSED -lt $TIMEOUT ]; do
    STATUS=$(redis-cli INFO persistence | grep rdb_bgsave_in_progress | cut -d: -f2)
    if [ "$STATUS" -eq 0 ]; then
        break
    fi
    sleep 1
    ELAPSED=$((ELAPSED + 1))
done

# 检查并复制
if [ -f "${REDIS_DIR}/dump.rdb" ]; then
    cp "${REDIS_DIR}/dump.rdb" "${BACKUP_DIR}/dump_$(date +%Y%m%d_%H%M).rdb"
    echo "备份成功: $(du -h ${BACKUP_DIR}/dump_*.rdb | tail -1)"
fi

4.2 AOF备份

# 触发AOF重写(压缩AOF文件)
redis-cli BGREWRITEAOF

# 备份AOF
cp /var/lib/redis/appendonly.aof /data/backup/redis/aof_$(date +%Y%m%d_%H%M).aof

# 检查AOF是否损坏
redis-check-aof /var/lib/redis/appendonly.aof
# 修复
redis-check-aof --fix /var/lib/redis/appendonly.aof

五、自动化备份框架

5.1 统一备份脚本

#!/bin/bash
# unified_backup.sh

set -euo pipefail

# 配置
BACKUP_ROOT="/data/backup"
RETENTION_DAYS=30
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx"

# 日志
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a /var/log/backup.log
}

# 通知
notify() {
    local status="$1" msg="$2"
    curl -s -X POST "$SLACK_WEBHOOK" \
        -H 'Content-type: application/json' \
        -d "{\"text\":\"[$status] 备份任务: $msg\"}" > /dev/null
}

# MySQL备份
backup_mysql() {
    log "开始MySQL备份..."
    mysqldump --single-transaction --all-databases \
        | gzip > "${BACKUP_ROOT}/mysql/full_$(date +%Y%m%d).sql.gz"
    local rc=$?
    log "MySQL备份完成 (exit=$rc)"
    return $rc
}

# 清理旧备份
cleanup() {
    log "清理${RETENTION_DAYS}天前的备份..."
    find "${BACKUP_ROOT}" -type f -mtime +"${RETENTION_DAYS}" -delete
}

# 主流程
main() {
    log "===== 备份任务开始 ====="
    local failed=0
    
    backup_mysql || { failed=1; notify "FAIL" "MySQL备份失败"; }
    backup_postgresql || { failed=1; notify "FAIL" "PG备份失败"; }
    
    cleanup
    
    if [ $failed -eq 0 ]; then
        notify "OK" "所有备份任务完成"
    fi
    log "===== 备份任务结束 ====="
}

main "$@"

六、灾难恢复演练

6.1 演练流程

1. 准备阶段
   - 确认备份文件可用
   - 准备演练环境
   
2. 执行阶段
   - 模拟故障(停止数据库)
   - 执行恢复流程
   - 计时记录
   
3. 验证阶段
   - 数据完整性检查
   - 业务功能测试
   - 性能基准对比
   
4. 复盘阶段
   - 记录耗时
   - 发现问题
   - 优化预案

6.2 恢复检查清单

□ 备份文件存在且大小>0
□ 备份文件MD5校验通过
□ 能在测试环境成功恢复
□ 数据行数与预期一致
□ 关键表CHECKSUM一致
□ 应用能正常连接
□ 业务查询正常返回

总结

备份恢复的黄金法则:

  1. 3-2-1原则:3份备份、2种介质、1份异地
  2. 自动化:脚本+定时任务,杜绝手工操作
  3. 验证:未验证的备份等于没有备份
  4. 文档:恢复步骤要清晰,紧急时刻不用想
  5. 演练:每季度至少一次灾难恢复演练
分享:

相关文章