灾备恢复

本文涵盖的内容

本文描述 AuraBoot 的灾难恢复策略:需要备份哪些内容、如何验证恢复可行,以及出现问题时的完整操作步骤。两个核心术语贯穿全文。RTO(Recovery Time Objective,恢复时间目标)是从故障声明到服务恢复的最大允许时长。RPO(Recovery Point Objective,恢复点目标)是可接受的最大数据丢失量,以时间衡量。本文中的所有决策——备份频率、复制拓扑、演练节奏——均源于下方各部署层级的 RTO/RPO 目标。

RTO 与 RPO 分级

部署层级典型配置RTO 目标RPO 目标
单节点单台主机,每日 pg_dump,无备库< 2 小时< 24 小时
HA 集群主库 + 流式复制备库 + WAL 归档< 30 分钟< 5 分钟
多地域HA 集群 + 跨地域 WAL 或副本< 10 分钟< 1 分钟

HA 集群层级是平台默认的生产拓扑。该层级 P0 故障(服务全不可用)的 MTTR 目标为 < 15 分钟。单节点部署以 RTO/RPO 换取简单性,该取舍仅适用于开发和预发布环境。

四类必须保护的资产

PostgreSQL 数据是所有应用状态的权威存储:租户、用户、元数据模型、页面 Schema、命令定义、插件配置,以及每一张动态业务表(mt_*)。必须同时使用逻辑备份(pg_dump,便携性强)和物理基础备份(pg_basebackup,支持快速 PITR)。没有任何其他方式能替代丢失或损坏的 PostgreSQL 备份。

**对象存储(MinIO / S3 兼容)**保存上传的文件、附件、报表导出和爬虫产物。对象存储对应用层而言是只写的——文件写入后,应用只通过键值读取。通过桶复制或定期同步到独立存储端点进行备份。不要依赖应用数据库来重建哪些文件存在;将对象存储视为独立的持久化资产单独管理。

Redis 状态保存分布式锁、会话令牌、限流桶和 L2 元数据缓存。Redis 数据本质上是短暂的:会话过期、锁释放、缓存从 PostgreSQL 重建。冷重启时 Redis 为空会导致预热期延迟峰值(典型元数据集约需 1.5 秒),但不会产生数据丢失。Sentinel 或集群拓扑覆盖 Redis 高可用;不需要为灾备目的对 Redis 做快照。

密钥与配置——环境变量、application-prod.yml 覆盖配置、TLS 证书和加密密钥——必须存放在密钥管理系统或等效的版本化存储中,而不只是服务器文件系统上。恢复了 PostgreSQL 但丢失了 ab_cloud_config 加密密钥的恢复不是成功的恢复。将密钥视为独立的备份轴,制定专属的轮换和恢复流程。

PostgreSQL 备份策略

AuraBoot 使用两种互补的备份方法。每日逻辑备份(pg_dump)速度快且便于移植。每周物理基础备份(pg_basebackup)结合持续 WAL 归档,可将数据库恢复到保留窗口内的任意时间点(PITR)。

WAL 归档——首先启用:

# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /var/wal-archive/%f && cp %p /var/wal-archive/%f'
wal_keep_size = 1GB
checkpoint_completion_target = 0.9
checkpoint_timeout = 5min
max_wal_size = 1GB

在依赖 PITR 之前,验证归档进程健康:

psql -U auraboot -d aura_boot -c "SELECT * FROM pg_stat_archiver;"
# failed_count 必须为 0;last_archived_time 必须是最近时间

每周物理全备:

PGPASSWORD="$REPLICATION_PASSWORD" pg_basebackup \
    -h "$DB_HOST" \
    -U replicator \
    --pgdata=/var/backups/auraboot/weekly/basebackup-$(date +%Y%m%d) \
    --format=tar \
    --gzip \
    --compress=9 \
    --wal-method=stream \
    --checkpoint=fast \
    --progress

每日逻辑备份(便携、可验证):

pg_dump \
    -h "$DB_HOST" -U auraboot -d aura_boot \
    --format=custom --compress=9 \
    --file=/var/backups/auraboot/daily/aura_boot-$(date +%Y%m%d-%H%M%S).dump

# 完整性检查——列出内容而不实际恢复
pg_restore --list /var/backups/auraboot/daily/aura_boot-*.dump > /dev/null

保留策略:

备份类型本地保留异地保留
每日 pg_dump7 天对象存储 30 天
每周 pg_basebackup4 周3 个月
WAL 归档直到被基础备份覆盖后再保留 7 天与异地存储同步

PITR 恢复到目标时间点:

# 1. 停止应用服务
systemctl stop auraboot && systemctl stop postgresql

# 2. 解压目标时间前最近的基础备份
rm -rf /var/lib/postgresql/data/*
tar -xzf /var/backups/auraboot/weekly/basebackup-20260410/base.tar.gz \
    -C /var/lib/postgresql/data/
chown -R postgres:postgres /var/lib/postgresql/data
chmod 700 /var/lib/postgresql/data

# 3. 配置 PITR(PostgreSQL 12+)
cat >> /var/lib/postgresql/data/postgresql.conf <<EOF
restore_command = 'cp /var/wal-archive/%f %p'
recovery_target_time = '2026-04-11 14:30:00'
recovery_target_action = 'promote'
EOF
touch /var/lib/postgresql/data/recovery.signal

# 4. 启动并观察 WAL 重放进度
systemctl start postgresql
tail -f /var/log/postgresql/postgresql-$(date +%Y-%m-%d).log

对象存储与文件备份

在主对象存储端点和地理位置分离的备用端点之间启用桶复制。至少每晚执行一次同步:

# 通用 S3 兼容同步(根据所用工具调整)
mc mirror --overwrite --remove primary/auraboot-files secondary/auraboot-files-backup

对象存储丢失后,可以从 PostgreSQL 重建的内容:ab_file 中的文件元数据记录。无法重建的内容:实际的文件字节。这种不对称意味着,无论 PostgreSQL 多健康,在没有备份的情况下丢失对象存储就是永久性数据丢失。

不要将本地磁盘 MinIO 用于生产持久化。本地 MinIO 仅适合开发环境和单节点预发布环境。生产环境应将 MinIO 配置为分布式模式,或将平台指向已启用复制功能的外部 S3 兼容服务。

跨地域故障切换流程

按顺序执行以下步骤。不要跳过复制延迟检查——在提升复制落后几分钟的备库之前,必须先评估并接受该 RPO 损失。

  1. 检测并定性故障。 确认主库不可达:pg_isready -h <主库IP> -p 5432 返回无响应。在提升备库之前,通过 pg_stat_replication 检查复制延迟。

  2. 检查复制延迟:

    psql -h <备库IP> -U auraboot -d aura_boot -c \
      "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::INT AS lag_seconds;"
  3. 提升备库:

    psql -h <备库IP> -U auraboot -c "SELECT pg_promote();"
    # 验证:pg_is_in_recovery() 必须返回 false
    psql -h <备库IP> -U auraboot -d aura_boot -c "SELECT pg_is_in_recovery();"
  4. 切换 DNS 或负载均衡器上游,将 db.internal 指向已提升备库的 IP。如果直接使用连接字符串环境变量,在每个应用节点上更新 DATASOURCE_URL

  5. 重启应用服务并验证健康状态:

    systemctl restart auraboot
    curl -s http://localhost:6443/api/health | python3 -m json.tool
  6. 验证数据完整性(见下方「恢复后数据验证」章节)。

  7. 通知相关人员并记录事件。 记录实际故障切换时长和提升时的复制延迟,作为事后 RTO/RPO 实测数据。

恢复演练检查清单

每季度进行一次完整恢复演练。未经测试的恢复等同于没有备份。每次演练覆盖以下项目:

  • 在隔离主机上执行 PITR,目标时间点为演练窗口前 2 小时
  • 验证 recovery.signal 已被消费,PostgreSQL 已退出恢复模式
  • 从最近的 pg_dump 文件全量恢复到 aura_boot_drill_$(date +%Y%m%d) 数据库
  • 插件重新导入:导入至少一个生产插件包,确认返回 success: true
  • 元数据缓存预热:启动应用连接到恢复后的数据库,确认 CacheWarmupRunner 无报错完成
  • Redis 冷启动:清空 Redis,重启应用,测量前 10 个请求的延迟(预热开销不应超过 3 秒)
  • 冒烟验证命令:curl /api/health,获取租户列表,执行一个动态列表查询
  • 记录从「开始恢复」到「冒烟验证通过」的墙钟时间,即实测 RTO;与本层级目标对比
  • 将结果记录在演练报告模板中,将发现的差距记录为跟进事项,指定负责人和截止时间

恢复后数据验证

在宣布恢复完成并重开生产流量之前,执行以下检查。

-- 核心表行数——与预期基线对比
SELECT 'ab_user'        AS tbl, COUNT(*) AS rows FROM ab_user
UNION ALL
SELECT 'ab_tenant',              COUNT(*)         FROM ab_tenant
UNION ALL
SELECT 'ab_meta_model',          COUNT(*)         FROM ab_meta_model
UNION ALL
SELECT 'ab_page_schema',         COUNT(*)         FROM ab_page_schema
UNION ALL
SELECT 'ab_command_definition',  COUNT(*)         FROM ab_command_definition
ORDER BY tbl;

-- 动态业务表存在性(每个插件发布 mt_* 表)
SELECT COUNT(*) AS dynamic_table_count
FROM information_schema.tables
WHERE table_name LIKE 'mt_%' AND table_schema = 'public';

-- 审计日志连续性——间隔不应超过预期写入频率的 2 倍
SELECT MAX(changed_at) AS last_audit_entry,
       NOW() - MAX(changed_at) AS staleness
FROM ab_data_change_log;

-- 活跃租户可正常解析
SELECT name, status FROM ab_tenant WHERE status = 'active' LIMIT 5;

需要断言的关键不变量:

  • ab_tenant 至少有一条 active 记录。
  • ab_meta_model 数量与恢复前一致(插件模型不会在恢复时重新创建,它们从 dump 文件中恢复)。
  • ab_data_change_log 的最新时间戳在恢复点的预期 RPO 窗口内。
  • 活跃插件引用的所有 mt_* 表都存在于 information_schema.tables 中。

如果任何本不应为零的计数为零,立即停止并排查,不要在此之前恢复流量。部分恢复比彻底失败更危险。

常见陷阱

陷阱危害
WAL 归档磁盘写满,归档进程静默暂停pg_stat_archiver.failed_count 持续增加;未触发告警的情况下 PITR 窗口缩减至零
pg_basebackup 未加 --wal-method=stream基础备份数据一致,但备份起止之间的 WAL 间隙未捕获
恢复目标主机的 PostgreSQL 大版本不同pg_restore 可能成功,但目录格式不兼容;始终保持版本一致
密钥未入库——加密密钥只在服务器文件系统上恢复后数据库 + 密钥丢失 = 所有加密列均不可读
从未进行过恢复演练第一次真实恢复耗时是预估的 3 倍,因为存在未知的操作细节
未确认复制延迟就提升备库接受了未经测量的更大 RPO 损失
将 Redis Sentinel 自动切换等同于 PostgreSQL 故障切换Redis 会话丢失导致用户被登出;应提前规划宽限期提示
恢复后未验证 ab_data_change_log 连续性审计链静默断裂;合规审计和事故调查失去追溯依据

后续步骤

  • 备份与恢复 — 完整备份脚本、cron 配置及恢复 Runbook
  • 可观测性 — 备份成功率、复制延迟和 WAL 归档健康的指标与告警
  • 性能调优 — RTO 受 PostgreSQL WAL 重放速度影响;在真正需要之前完成调优
  • 负载均衡 — 故障切换过程中的 DNS 和上游切换模式

企业版说明 — 托管式跨地域自动故障切换(含自动 DNS 提升)、带防篡改审计链的签名备份产物溯源(SHA-256 清单),以及基于真实恢复演练遥测数据的 RTO/RPO SLA 实时仪表板,均为企业版功能。社区版可完整使用本文档中描述的所有备份机制和操作手册;区别在于托管编排层和合规级别的产物签名,而非底层的 PostgreSQL 与 WAL 工具本身。