备份与恢复演练
备份只有在能成功恢复的时候才有价值。许多团队在真正需要恢复数据时才发现备份损坏、不完整或恢复流程不可执行。定期的备份恢复演练是确保业务连续性的关键实践。
为什么要做恢复演练
Section titled “为什么要做恢复演练”| 风险 | 后果 | 演练如何帮助 |
|---|---|---|
| 备份文件损坏 | 无法恢复任何数据 | 验证备份完整性 |
| 恢复流程未文档化 | 故障时手忙脚乱,恢复时间过长 | 形成标准操作手册 |
| 备份数据不完整 | 关键数据缺失 | 发现遗漏的备份对象 |
| 人员变动 | 只有特定人员会操作恢复 | 团队成员都能执行 |
| 环境差异 | 备份在测试环境无法恢复 | 暴露环境兼容性问题 |
准备一台与生产环境配置相似的测试服务器:
# 测试服务器基本信息确认cat /etc/redhat-releaseuname -rdf -hfree -h确保测试环境安装了必要的恢复工具:
dnf install -y \ borgbackup \ mysql \ postgresql \ tar \ rsync \ gzip \ xz获取备份清单
Section titled “获取备份清单”记录需要验证的备份源:
# 列出可用的备份存档# Borg 备份borg list /backup/borg-repo
# 或列出远程备份borg list ssh://backup@backup-server/repo
# 记录最新备份的时间戳borg info /backup/borg-repo::latest第 1 阶段:备份完整性验证
Section titled “第 1 阶段:备份完整性验证”在恢复之前,先确认备份文件本身是完整的。
Borg 备份校验
Section titled “Borg 备份校验”# 校验仓库完整性borg check /backup/borg-repo
# 校验特定存档borg check --archives-only /backup/borg-repo::2026-03-24_0200
# 详细校验(包含数据块验证,耗时较长)borg check --verify-data /backup/borg-repotar 备份校验
Section titled “tar 备份校验”# 测试 tar 包完整性tar -tzf /backup/full-backup-20260324.tar.gz > /dev/nullecho "Exit code: $?"# Exit code 为 0 表示正常
# 如果使用了 gpg 加密gpg --decrypt /backup/full-backup-20260324.tar.gz.gpg | tar -tz > /dev/nullrsync 备份校验
Section titled “rsync 备份校验”# 对比源和备份的文件差异rsync -avnc /source/path/ /backup/rsync-mirror/ > /tmp/rsync-diff.txtcat /tmp/rsync-diff.txt
# 差异为空则表示一致第 2 阶段:文件恢复测试
Section titled “第 2 阶段:文件恢复测试”2.1 恢复系统配置文件
Section titled “2.1 恢复系统配置文件”# 创建恢复临时目录mkdir -p /tmp/restore-test
# 从 Borg 恢复特定目录cd /tmp/restore-testborg extract /backup/borg-repo::latest etc/
# 对比关键配置文件diff /tmp/restore-test/etc/ssh/sshd_config /etc/ssh/sshd_configdiff /tmp/restore-test/etc/firewalld/ /etc/firewalld/ -r2.2 恢复应用数据
Section titled “2.2 恢复应用数据”# 从 Borg 恢复应用目录cd /tmp/restore-testborg extract /backup/borg-repo::latest var/www/myapp/
# 验证文件数量和大小find /tmp/restore-test/var/www/myapp -type f | wc -ldu -sh /tmp/restore-test/var/www/myapp2.3 验证文件权限和属性
Section titled “2.3 验证文件权限和属性”恢复后必须检查文件权限是否正确:
# 检查关键目录的权限ls -la /tmp/restore-test/etc/ssh/ls -la /tmp/restore-test/var/www/myapp/
# 检查 SELinux 上下文ls -Z /tmp/restore-test/var/www/myapp/2.4 清理
Section titled “2.4 清理”rm -rf /tmp/restore-test第 3 阶段:MySQL / MariaDB 恢复测试
Section titled “第 3 阶段:MySQL / MariaDB 恢复测试”3.1 准备测试环境
Section titled “3.1 准备测试环境”# 在测试服务器上安装 MySQL/MariaDBdnf install -y mysql-serversystemctl start mysqld
# 创建专用测试数据库mysql -u root -e "CREATE DATABASE restore_test;"3.2 恢复 mysqldump 备份
Section titled “3.2 恢复 mysqldump 备份”# 查看备份文件信息ls -lh /backup/mysql/mydb-20260324.sql.gzzcat /backup/mysql/mydb-20260324.sql.gz | head -30
# 恢复到测试数据库zcat /backup/mysql/mydb-20260324.sql.gz | mysql -u root restore_test3.3 验证数据一致性
Section titled “3.3 验证数据一致性”# 检查表数量mysql -u root -e "SELECT COUNT(*) AS table_count FROM information_schema.tables WHERE table_schema='restore_test';"
# 检查各表行数mysql -u root -e "SELECT table_name, table_rowsFROM information_schema.tablesWHERE table_schema='restore_test'ORDER BY table_name;"
# 抽样检查关键数据mysql -u root -e "SELECT COUNT(*) FROM restore_test.users;"mysql -u root -e "SELECT COUNT(*) FROM restore_test.orders;"
# 检查最新记录的时间戳(确认备份时间点)mysql -u root -e "SELECT MAX(created_at) AS latest_record FROM restore_test.orders;"3.4 恢复 XtraBackup 物理备份(如果使用)
Section titled “3.4 恢复 XtraBackup 物理备份(如果使用)”# 准备备份xtrabackup --prepare --target-dir=/backup/xtrabackup/20260324
# 恢复到测试目录systemctl stop mysqldxtrabackup --copy-back --target-dir=/backup/xtrabackup/20260324 --datadir=/var/lib/mysql-test
# 修正权限chown -R mysql:mysql /var/lib/mysql-test
# 使用测试数据目录启动mysqld --datadir=/var/lib/mysql-test --port=3307 &
# 验证mysql -P 3307 -u root -e "SHOW DATABASES;"3.5 清理
Section titled “3.5 清理”mysql -u root -e "DROP DATABASE restore_test;"第 4 阶段:PostgreSQL 恢复测试
Section titled “第 4 阶段:PostgreSQL 恢复测试”4.1 准备测试环境
Section titled “4.1 准备测试环境”# 在测试服务器上安装 PostgreSQLdnf install -y postgresql-serverpostgresql-setup --initdbsystemctl start postgresql4.2 恢复 pg_dump 备份
Section titled “4.2 恢复 pg_dump 备份”# 查看备份信息ls -lh /backup/postgresql/mydb-20260324.sql.gzzcat /backup/postgresql/mydb-20260324.sql.gz | head -30
# 创建测试数据库和用户sudo -u postgres createdb restore_testsudo -u postgres createuser --no-password testuser
# 恢复zcat /backup/postgresql/mydb-20260324.sql.gz | sudo -u postgres psql restore_test4.3 恢复自定义格式备份
Section titled “4.3 恢复自定义格式备份”# 如果使用 pg_dump -Fc 格式sudo -u postgres pg_restore -d restore_test /backup/postgresql/mydb-20260324.dump
# 仅恢复特定表sudo -u postgres pg_restore -d restore_test -t users /backup/postgresql/mydb-20260324.dump4.4 验证数据一致性
Section titled “4.4 验证数据一致性”# 检查表数量sudo -u postgres psql restore_test -c "SELECT COUNT(*) AS table_countFROM information_schema.tablesWHERE table_schema = 'public';"
# 检查各表行数sudo -u postgres psql restore_test -c "SELECT schemaname, relname AS table_name, n_live_tup AS row_countFROM pg_stat_user_tablesORDER BY relname;"
# 抽样检查sudo -u postgres psql restore_test -c "SELECT COUNT(*) FROM users;"sudo -u postgres psql restore_test -c "SELECT MAX(created_at) FROM orders;"
# 检查索引完整性sudo -u postgres psql restore_test -c "REINDEX DATABASE restore_test;"4.5 恢复基于 WAL 的时间点恢复(PITR)
Section titled “4.5 恢复基于 WAL 的时间点恢复(PITR)”# 准备恢复目录mkdir -p /var/lib/pgsql/restore-test
# 恢复基础备份tar xzf /backup/postgresql/base-20260324.tar.gz -C /var/lib/pgsql/restore-test/
# 配置恢复参数cat > /var/lib/pgsql/restore-test/postgresql.auto.conf << 'EOF'restore_command = 'cp /backup/postgresql/wal/%f %p'recovery_target_time = '2026-03-24 12:00:00'recovery_target_action = 'promote'EOF
# 创建恢复信号文件touch /var/lib/pgsql/restore-test/recovery.signal
# 修正权限chown -R postgres:postgres /var/lib/pgsql/restore-test/
# 以不同端口启动恢复实例sudo -u postgres pg_ctl start -D /var/lib/pgsql/restore-test -o "-p 5433"
# 验证恢复时间点psql -p 5433 -U postgres -c "SELECT pg_last_xact_replay_timestamp();"4.6 清理
Section titled “4.6 清理”sudo -u postgres dropdb restore_test# 如果启动了 PITR 测试实例sudo -u postgres pg_ctl stop -D /var/lib/pgsql/restore-testrm -rf /var/lib/pgsql/restore-test第 5 阶段:记录演练结果
Section titled “第 5 阶段:记录演练结果”每次演练都必须详细记录结果。使用以下模板:
演练报告模板
Section titled “演练报告模板”===== 备份恢复演练报告 =====日期:2026-03-25执行人:[姓名]环境:测试服务器 restore-test-01
--- 备份完整性验证 ---[PASS/FAIL] Borg 仓库校验[PASS/FAIL] 数据块完整性备注:
--- 文件恢复 ---[PASS/FAIL] 系统配置文件恢复[PASS/FAIL] 应用数据恢复[PASS/FAIL] 文件权限正确备注:
--- MySQL 恢复 ---[PASS/FAIL] 备份文件加载成功[PASS/FAIL] 表数量一致:生产 XX 表,恢复 XX 表[PASS/FAIL] 行数一致[PASS/FAIL] 最新数据时间戳符合预期恢复耗时:XX 分钟备注:
--- PostgreSQL 恢复 ---[PASS/FAIL] 备份文件加载成功[PASS/FAIL] 表数量一致:生产 XX 表,恢复 XX 表[PASS/FAIL] 行数一致[PASS/FAIL] 索引重建成功恢复耗时:XX 分钟备注:
--- 发现的问题 ---1. [描述问题及影响]2. [描述问题及影响]
--- 改进措施 ---1. [具体改进行动及负责人]2. [具体改进行动及负责人]
--- 下次演练计划 ---日期:2026-06-25范围:[全量/增量/特定系统]第 6 阶段:建立季度演练制度
Section titled “第 6 阶段:建立季度演练制度”| 季度 | 月份 | 演练内容 | 预计耗时 |
|---|---|---|---|
| Q1 | 3 月 | 全量恢复演练(文件 + 数据库) | 4 小时 |
| Q2 | 6 月 | 数据库恢复专项 + PITR 测试 | 2 小时 |
| Q3 | 9 月 | 全量恢复演练(含灾难恢复场景) | 4 小时 |
| Q4 | 12 月 | 文件恢复 + 备份策略年度评审 | 3 小时 |
# 创建季度演练提醒的 cron 任务cat > /etc/cron.d/backup-drill-reminder << 'EOF'# 每季度第一个工作日发送提醒0 9 1 3,6,9,12 * root echo "备份恢复演练提醒:请在本月内完成季度备份恢复演练。" | mail -s "[ACTION] 季度备份恢复演练" ops-team@example.comEOF自动化验证脚本
Section titled “自动化验证脚本”除了人工演练,也应该自动化日常的备份校验:
cat > /usr/local/bin/backup-verify.sh << 'SCRIPT'#!/bin/bashset -euo pipefail
LOG="/var/log/backup-verify.log"ALERT_EMAIL="ops-team@example.com"ERRORS=0
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG"}
log "===== 开始备份验证 ====="
# 1. 检查 Borg 备份if borg check /backup/borg-repo 2>> "$LOG"; then log "[PASS] Borg 仓库完整性检查通过"else log "[FAIL] Borg 仓库完整性检查失败" ((ERRORS++))fi
# 2. 检查最近备份的时间(不超过 25 小时)LATEST=$(borg list --sort-by timestamp --last 1 --format '{time}' /backup/borg-repo)LATEST_TS=$(date -d "$LATEST" +%s)NOW_TS=$(date +%s)AGE_HOURS=$(( (NOW_TS - LATEST_TS) / 3600 ))
if [ "$AGE_HOURS" -lt 25 ]; then log "[PASS] 最近备份时间在 ${AGE_HOURS} 小时前"else log "[FAIL] 最近备份已过期:${AGE_HOURS} 小时前" ((ERRORS++))fi
# 3. 检查备份大小(不应为零或异常小)LATEST_SIZE=$(borg info /backup/borg-repo::latest --json | python3 -c "import sys,json; print(json.load(sys.stdin)['archives'][0]['stats']['original_size'])")if [ "$LATEST_SIZE" -gt 1048576 ]; then log "[PASS] 备份大小正常:$LATEST_SIZE bytes"else log "[FAIL] 备份大小异常:$LATEST_SIZE bytes" ((ERRORS++))fi
# 报告结果if [ "$ERRORS" -gt 0 ]; then log "验证完成,发现 ${ERRORS} 个问题" tail -20 "$LOG" | mail -s "[ALERT] 备份验证失败 (${ERRORS} errors)" "$ALERT_EMAIL"else log "验证完成,全部通过"fiSCRIPT
chmod +x /usr/local/bin/backup-verify.sh设置每日自动验证:
cat > /etc/cron.d/backup-verify << 'EOF'0 6 * * * root /usr/local/bin/backup-verify.shEOF常见问题与解决方案
Section titled “常见问题与解决方案”| 问题 | 原因 | 解决方案 |
|---|---|---|
| 恢复后数据库启动失败 | 版本不匹配 | 确保测试环境与生产使用相同的数据库版本 |
| 恢复后文件权限错误 | tar 解压未保留属性 | 使用 tar -xpf 保留权限,恢复后运行 restorecon -Rv |
| Borg 报告仓库损坏 | 备份过程中断或磁盘故障 | 运行 borg check --repair;检查备份磁盘健康状态 |
| 恢复时间过长 | 备份数据量大 | 考虑增量恢复策略;使用更快的存储介质 |
| WAL 文件缺失 | 归档配置错误 | 检查 archive_command 配置;确保归档目录空间充足 |
备份恢复演练不是一次性任务,而是持续的运维实践。关键要点:
- 验证第一 - 没有验证过的备份不可信
- 文档先行 - 每次演练都产出可执行的操作文档
- 定期执行 - 至少每季度一次完整演练
- 全员参与 - 不依赖单一人员
- 持续改进 - 每次演练后回顾并优化流程