恢复演练与灾备意识
"有备份"不代表"能恢复"。恢复能力必须被演练过。
恢复流程
graph TD
A[故障发生] --> B[确认故障范围]
B --> C{影响数据库?}
C -->|是| D[选择恢复点 RTO/RPO]
C -->|否| E[仅恢复文件/配置]
D --> F[在测试机验证备份完整性]
F --> G[恢复到生产 / 临时实例]
G --> H[验证记录数 / 业务功能]
H --> I[重新放流量]
E --> I
RTO 与 RPO:两个必须回答的数字
| 指标 | 全称 | 含义 | 决定因素 |
|---|---|---|---|
| RTO | Recovery Time Objective | 从故障到恢复服务的最大容忍时长 | 备份存储位置、恢复脚本是否自动化 |
| RPO | Recovery Point Objective | 最多能丢失多长时间的数据 | 备份频率(每日 = 最多丢 24 小时) |
示例目标(中小型项目):
| 场景 | RTO 目标 | RPO 目标 | 备份方案 |
|---|---|---|---|
| 博客/文档站 | 4 小时 | 24 小时 | 每日全量备份 |
| 电商独立站 | 1 小时 | 1 小时 | 每小时增量 + 每日全量 |
| 支付/金融 | 15 分钟 | 0(接近零) | 实时主从复制 + 备份 |
恢复演练步骤(季度必做)
PostgreSQL 恢复演练
# === 在独立测试机上执行(不要在生产机器上) ===
# 1. 从对象存储下载最新备份
rclone copy s3:my-prod-backups/db/db-2026-03-22.dump.enc /tmp/
# 2. 解密
openssl enc -d -aes-256-cbc -pbkdf2 \
-in /tmp/db-2026-03-22.dump.enc \
-out /tmp/db-restore-test.dump \
-pass file:/etc/backup/backup.key
# 3. 创建测试数据库
createdb -U postgres restore_test
# 4. 恢复
pg_restore -U postgres -d restore_test -j 4 /tmp/db-restore-test.dump
# 5. 验证完整性(关键表记录数对比)
psql -U postgres restore_test -c "SELECT COUNT(*) FROM users;"
psql -U postgres restore_test -c "SELECT COUNT(*) FROM orders;"
# 对比生产数据库相同查询的结果,误差应 < 1%(取决于演练时与备份时的时间差)
# 6. 清理
dropdb -U postgres restore_test
rm /tmp/db-restore-test.dump /tmp/db-2026-03-22.dump.enc
MySQL 恢复演练
# 1. 下载备份
rclone copy s3:my-prod-backups/db/mydb-2026-03-22.sql.gz /tmp/
# 2. 创建测试库
mysql -u root -p -e "CREATE DATABASE restore_test;"
# 3. 恢复
gunzip < /tmp/mydb-2026-03-22.sql.gz | mysql -u root -p restore_test
# 4. 验证
mysql -u root -p restore_test -e "SELECT COUNT(*) FROM users;"
# 5. 清理
mysql -u root -p -e "DROP DATABASE restore_test;"
备份完整性快速验证(不需要全量恢复)
# PostgreSQL:列出 dump 内容(不执行恢复)
pg_restore --list /backup/db-2026-03-22.dump | wc -l
# 输出行数 > 10 说明 dump 非空,基本可用
# 检查 dump 文件是否可读(压缩未损坏)
pg_restore --list /backup/db-2026-03-22.dump > /dev/null && echo "OK" || echo "CORRUPT"
# MySQL:检查压缩文件完整性
gunzip -t /backup/mydb-2026-03-22.sql.gz && echo "OK" || echo "CORRUPT"
灾备场景分类
| 故障级别 | 示例 | 恢复方式 | 预计 RTO |
|---|---|---|---|
| 应用层 | 代码 bug 导致数据错误 | 回滚代码 + 修复数据 | < 30 分钟 |
| 数据库 | 误删表/行 | 从最近备份恢复到测试机,导出差异数据 | 1–4 小时 |
| 服务器 | 云主机宕机 | 从快照创建新实例 | 30–60 分钟 |
| 存储 | 磁盘损坏 | 从对象存储恢复文件 | 2–8 小时(取决于数据量) |
| 区域 | 云厂商整个区域故障 | 切换到备用区域(需提前准备) | 数小时 |
常见误区
| 误区 | 正确做法 |
|---|---|
| "备份脚本跑了就没问题" | 定期验证备份文件完整性(每月一次 pg_restore --list) |
| "恢复在生产机器上直接操作" | 先在测试机恢复验证,确认无误再切换 |
| "RTO 越短越好,不惜成本" | RTO 目标应与业务损失挂钩,过度投资不合理 |
| "只有数据库需要备份" | 用户上传文件、SSL 证书、配置文件同样需要备份 |
本节执行清单
- [ ] 写出你项目的 RTO 和 RPO 目标(填到运维手册)
- [ ] 完成一次端到端恢复演练(在测试机恢复并验证记录数)
- [ ] 验证备份文件完整性(
pg_restore --list或gunzip -t) - [ ] 明确恢复负责人:谁来执行、谁来验证、谁来决策放量
- [ ] 把恢复步骤写成 Runbook,存放在团队知识库
下一章:日志、监控与告警——恢复之外,先要能及时发现问题。