Files
Genarrative/.hermes/plans/2026-05-11_205645-genarrative-disaster-recovery.md
kdletters 4dfa8452db
Some checks failed
CI / verify (push) Has been cancelled
docs: add disaster recovery plan draft
2026-05-12 14:13:53 +08:00

16 KiB
Raw Permalink Blame History

Genarrative 容灾方案设计计划

For Hermes: Use subagent-driven-development skill to implement this plan task-by-task.

Goal: 基于当前 Genarrative 单机生产部署、Jenkins 流水线、SpacetimeDB 与 Rust api-server 架构,补齐一套可落地、可演练、可审计的容灾方案。

Architecture: 首版容灾不引入复杂多活系统,优先围绕现有 systemd + Nginx + SpacetimeDB + api-server + Jenkins 单机生产推荐方案做“备份可恢复、版本可回滚、故障可切换、演练可复盘”。方案采用分层容灾入口层、静态资源层、API 服务层、SpacetimeDB 数据层、外部服务与密钥层、Jenkins/发布链路层。

Tech Stack: Nginx、systemd、SpacetimeDB self-hosting、Rust api-server / Axum、Jenkins Pipeline、Shell/Node.js 运维脚本、仓库 deploy/docs/technical/ 文档体系。


1. 当前上下文与已确认事实

1.1 当前生产部署口径

来自 docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md 的现状:

  • 生产为单机推荐方案,不使用 Docker。
  • 公网入口为 Nginx负责 HTTPS、静态站点、后台静态页面、维护页、/admin/api/ 与临时 /api/* 反向代理。
  • SpacetimeDB 作为 systemd 服务运行:
    • spacetimedb.service
    • 监听:127.0.0.1:3101
    • 数据根目录:/stdb
  • Rust api-server 作为 systemd 服务运行:
    • genarrative-api.service
    • 监听:127.0.0.1:8082
    • 环境文件:/etc/genarrative/api-server.env
  • 静态站点发布到 release/current 目录:
    • /opt/genarrative/releases/<version>/
    • /opt/genarrative/current
    • /srv/genarrative/web
  • 已有维护模式:
    • 开关文件:/var/lib/genarrative/maintenance/enabled
    • API 发布、SpacetimeDB 模块发布、数据库导入、服务器配置变更必须进入维护模式。
  • 已有数据库导入导出 Jenkins Job
    • Genarrative-Database-Export
    • Genarrative-Database-Import
    • 对应文件:jenkins/Jenkinsfile.production-database-exportjenkins/Jenkinsfile.production-database-import
  • 已有回滚基本口径:
    • Web 回滚:切 /srv/genarrative/web/opt/genarrative/current 到上一版本并 reload Nginx。
    • API 回滚:切 /opt/genarrative/current 到上一版本并重启 genarrative-api.service
    • SpacetimeDB 模块回滚:发布上一版本 spacetime_module.wasm
    • 数据回滚:使用导入流水线恢复指定备份,必须进入维护模式。

1.2 关键风险

  • 当前是单机生产拓扑,单机磁盘、系统盘、/stdb、Nginx 或公网 IP 故障会造成整体不可用。
  • SpacetimeDB 是核心业务真相,容灾重点必须围绕 /stdb、数据库导出产物、schema 迁移与导入验证。
  • /etc/genarrative/api-server.env 持有生产密钥,不能进入 Git也不能写进普通备份明文归档。
  • Jenkins controller/agent 同时承担构建、发布、备份、导入导出编排Jenkins 不可用时仍需要有最小人工恢复路径。
  • 外部 LLM、图片、语音、3D 网关不是本仓库可控系统,容灾只能做到配置降级、超时隔离、能力熔断与可观测告警。

2. 容灾目标

2.1 恢复目标建议

灾难类型 目标 RTO 目标 RPO 首版策略
Web 静态资源发布失败 5 分钟 0 release/current 原子切换回滚
API 发布失败 10 分钟 0 维护模式 + 上一版二进制回滚
SpacetimeDB wasm 发布失败 15 分钟 0 或按迁移前备份 发布前导出 + 上一版 wasm 回滚
数据误写 / 迁移失败 30-60 分钟 最近一次导出点 导入流水线从备份恢复
生产机磁盘损坏 2-4 小时 最近一次异地备份 新机器 provision + 拉取 release 包 + 恢复数据库
Jenkins controller 不可用 1-2 小时 不影响线上数据 手工脚本恢复 + Jenkins 备份恢复
第三方模型网关不可用 5-15 分钟内降级 不丢核心数据 配置切换 / 功能熔断 / 队列失败可重试

2.2 首版不做

  • 不做跨地域双活写入。
  • 不做 SpacetimeDB 在线主从复制,除非后续官方能力与项目压测验证支持。
  • 不让前端绕过 api-server 直接承担正式业务真相。
  • 不把生产密钥、Token、数据库 dump、Jenkins secret 写入 Git。
  • 不恢复旧 server-node、Express、PostgreSQL 或 Docker 一体化部署方案。

3. 总体容灾设计

3.1 分层策略

  1. 入口层Nginx / DNS / HTTPS

    • 保留 Nginx 配置模板在 Gitdeploy/nginx/genarrative.confdeploy/nginx/genarrative-dev-http.conf
    • 为 release 环境建立 Nginx 配置备份与证书恢复流程。
    • 明确 DNS 切换预案:生产机不可恢复时,将域名指向灾备机公网 IP。
  2. 静态资源层Web / Admin Web

    • 依赖 web.tar.gzweb.tar.gz.sha256release-manifest.json
    • 保留最近 N 个 release 目录与构建产物指针。
    • 回滚只切软链,不重新构建。
  3. API 服务层Rust api-server

    • 依赖归档的 api-server 二进制、checksum、release-manifest.json
    • /etc/genarrative/api-server.env 通过加密备份或密钥管理恢复,不进入 release 包。
    • systemd unit 由 deploy/systemd/genarrative-api.service 重新安装。
  4. 数据层SpacetimeDB

    • 每次高风险发布前强制导出数据库。
    • 定时导出:建议每天至少 1 次;高活跃期可每 4 小时 1 次。
    • 导出产物同时保存在Jenkins 归档 + 生产机 SERVER_BACKUP_DIRECTORY + 异地对象存储/备份机。
    • 导入前自动生成安全备份,保留当前实现口径。
  5. 发布编排层Jenkins

    • Jenkins Job、Jenkinsfile 在 Git 中可恢复。
    • Jenkins controller 配置、凭据、插件清单需要额外备份。
    • 发布 agent 使用 inbound + systemd 自恢复agent secret 仅存在目标机或 Jenkins 凭据。
  6. 密钥与外部服务层

    • /etc/genarrative/api-server.env、Jenkins Secret Text、SSH PEM、agent secret 不进 Git。
    • 制定密钥清单和恢复责任人,但不在仓库记录明文。
    • 外部服务配置按 docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md 维护必配项。

4. 建议新增/更新的文档

Task 1: 新增生产容灾技术方案文档

Objective: 形成团队可共享、可执行的容灾总纲。

Files:

  • Create: docs/technical/PRODUCTION_DISASTER_RECOVERY_PLAN_2026-05-11.md
  • Modify: docs/technical/README.md(若已有技术索引,应加入该文档入口)
  • Optional Modify: .hermes/shared-memory/project-overview.md(只加稳定索引,不写敏感信息)

文档必须覆盖:

  1. 容灾目标RTO/RPO 表。
  2. 生产资产清单Nginx、systemd、release/current、/stdb/etc/genarrative/api-server.env、Jenkins、构建产物。
  3. 备份策略:
    • 数据库导出。
    • release 产物保留。
    • Nginx/systemd/env 配置备份。
    • Jenkins 配置备份。
  4. 恢复流程:
    • Web 回滚。
    • API 回滚。
    • Stdb module 回滚。
    • 数据恢复。
    • 整机重建。
  5. 演练计划:每月一次数据库恢复演练,每季度一次整机重建演练。
  6. 安全边界:密钥不进 Git备份加密最小权限。
  7. 验收命令与人工检查清单。

Verification:

npm run check:encoding

Expected: PASS无中文乱码、无 BOM/CRLF 问题。


5. 建议新增/更新的脚本与流水线

Task 2: 增强数据库定时备份流水线

Objective: 把现有人工导出扩展为可定时执行、可异地保存、可审计的备份流程。

Files:

  • Modify: jenkins/Jenkinsfile.production-database-export
  • Modify: docs/technical/PRODUCTION_DISASTER_RECOVERY_PLAN_2026-05-11.md
  • Optional Create: scripts/deploy/production-backup-sync.sh

Implementation notes:

  • 在 Jenkins Job 中保留人工触发能力,同时建议配置 cron
    • development每天凌晨。
    • release每天凌晨或业务低峰。
  • 增加备份命名规范:
    • spacetime-migration-<database>-<yyyyMMdd-HHmmss>-<source_commit>.json
  • 增加 SERVER_BACKUP_DIRECTORY 默认建议:
    • /var/backups/genarrative/spacetimedb/<database>/
  • 增加备份保留策略:
    • 本机保留 7-14 天。
    • 异地保留 30-90 天。
  • 如实现 production-backup-sync.sh,只做同步框架,不硬编码真实 bucket、账号、endpoint 或密钥。

Verification:

bash -n scripts/deploy/production-backup-sync.sh
npm run check:encoding

Expected: shell 语法通过;文档编码检查通过。


Task 3: 增加灾备恢复 Runbook

Objective: 在真正故障时不依赖临场推理,按清单执行恢复。

Files:

  • Create: docs/operations/PRODUCTION_DR_RUNBOOK_2026-05-11.md
  • Modify: docs/operations/README.md(如果存在)

Runbook sections:

  1. 故障分级P0/P1/P2。
  2. 第一响应:
    • 判断 Nginx 是否在线。
    • 判断 genarrative-api.service 是否在线。
    • 判断 spacetimedb.service 是否在线。
    • 判断磁盘是否满。
    • 判断 Jenkins agent 是否在线。
  3. 快速止血:
    • 开维护模式。
    • 禁止继续发布。
    • 保留现场日志。
  4. 回滚流程:
    • Web 回滚命令。
    • API 回滚命令。
    • Stdb wasm 回滚命令。
  5. 数据恢复流程:
    • 选择备份。
    • dry-run 导入。
    • 确认导入。
    • smoke test。
  6. 整机重建流程:
    • 新机器 provision。
    • 恢复 /etc/genarrative/api-server.env
    • 恢复 SpacetimeDB 数据。
    • 发布最近稳定 release。
    • DNS 切换。
  7. 复盘模板。

Verification:

npm run check:encoding

Expected: PASS。


Task 4: 增加备份健康检查与恢复演练记录模板

Objective: 防止“有备份但不可恢复”。

Files:

  • Create: docs/operations/DR_DRILL_REPORT_TEMPLATE.md
  • Optional Create: scripts/deploy/verify-database-backup.sh
  • Modify: docs/technical/PRODUCTION_DISASTER_RECOVERY_PLAN_2026-05-11.md

建议检查项:

  • 备份文件存在且大小非 0。
  • 备份文件 checksum 可验证。
  • 备份文件可被 Genarrative-Database-Import dry-run 解析。
  • 最近一次备份时间未超过 RPO 阈值。
  • 导入后 /healthz 可用。
  • 首页、后台登录页、关键 API smoke 可用。

Verification:

bash -n scripts/deploy/verify-database-backup.sh
npm run check:encoding

Expected: PASS。


6. 具体恢复流程草案

6.1 Web 静态资源回滚

  1. 进入目标机。
  2. 查看 release 目录:/opt/genarrative/releases/
  3. 选择上一个稳定版本。
  4. 切换 /srv/genarrative/web/opt/genarrative/current 软链。
  5. 执行 Nginx 配置检查与 reload。
  6. 访问首页与后台静态入口。

验收:

  • / 返回最新稳定页面。
  • /admin/ 返回后台页面。
  • 静态资源无 404。

6.2 API 回滚

  1. 开维护模式。
  2. /opt/genarrative/current 到上一版包含稳定 api-server 的 release。
  3. 重启 genarrative-api.service
  4. 本机检查 http://127.0.0.1:8082/healthz
  5. 检查 Nginx 反代路径。
  6. 解除维护模式。

验收:

  • systemctl status genarrative-api.service 正常。
  • /healthz 正常。
  • 后台 /admin/api/* 基础接口正常。

6.3 SpacetimeDB 模块回滚

  1. 开维护模式。
  2. 确认目标数据库名与当前 API 环境一致:GENARRATIVE_SPACETIME_DATABASE
  3. 选择上一版 spacetime_module.wasm
  4. 使用 spacetimedb 服务用户发布上一版 wasm。
  5. 重启或检查 spacetimedb.service
  6. 检查 api-server 对目标数据库访问。
  7. 解除维护模式。

注意:如果 schema 已迁移且旧 wasm 不兼容当前数据,需要走数据恢复,不应直接盲目发布旧 wasm。

6.4 数据恢复

  1. 开维护模式。
  2. 从 Jenkins 归档或 SERVER_BACKUP_DIRECTORY 选择备份。
  3. 先执行导入 dry-run。
  4. 真正导入前生成当前数据库安全备份。
  5. 执行导入。
  6. 执行 smoke test。
  7. 解除维护模式。

必须记录:

  • 备份文件名。
  • 来源 Job/build number。
  • 恢复目标 database。
  • 恢复开始/结束时间。
  • 恢复后验证结果。

6.5 整机重建

  1. 准备新 Linux 机器。
  2. 接入 Jenkins release deploy agent或准备人工 SSH 运维路径。
  3. 运行 Genarrative-Server-Provision
    • 创建用户和目录。
    • 安装 SpacetimeDB。
    • 安装 systemd unit。
    • 安装 Nginx 配置。
  4. 恢复 /etc/genarrative/api-server.env
  5. 发布最近稳定 Web/API/Stdb 产物。
  6. 导入最近一次有效数据库备份。
  7. smoke test。
  8. 切 DNS。
  9. 观察 30-60 分钟。

7. 文件可能变更清单

首版落地建议按以下文件收口:

  • Create: docs/technical/PRODUCTION_DISASTER_RECOVERY_PLAN_2026-05-11.md
  • Create: docs/operations/PRODUCTION_DR_RUNBOOK_2026-05-11.md
  • Create: docs/operations/DR_DRILL_REPORT_TEMPLATE.md
  • Modify: docs/technical/README.md
  • Modify: docs/operations/README.md(若存在)
  • Modify: .hermes/shared-memory/project-overview.md(仅增加文档索引)
  • Optional Modify: jenkins/Jenkinsfile.production-database-export
  • Optional Modify: jenkins/Jenkinsfile.production-database-import
  • Optional Create: scripts/deploy/production-backup-sync.sh
  • Optional Create: scripts/deploy/verify-database-backup.sh

8. 测试与验收

8.1 文档与编码

npm run check:encoding

Expected: PASS。

8.2 Shell 脚本语法

如新增 shell 脚本:

bash -n scripts/deploy/production-backup-sync.sh
bash -n scripts/deploy/verify-database-backup.sh

Expected: PASS。

8.3 Jenkinsfile 静态检查

建议在 Jenkins UI 或本地 Jenkins Pipeline Linter 中检查:

  • jenkins/Jenkinsfile.production-database-export
  • jenkins/Jenkinsfile.production-database-import

Expected: Pipeline syntax valid。

8.4 演练验收

至少完成一次 development 目标演练:

  1. 触发 Genarrative-Database-Export
  2. 确认备份产物存在并归档。
  3. 使用 Genarrative-Database-Import dry-run 验证备份可解析。
  4. 不覆盖生产数据的前提下,记录演练报告。

release 目标演练应在业务低峰进行,并先确认通知渠道可用。


9. 风险、取舍与开放问题

9.1 风险

  • 单机生产仍存在物理机级单点故障,首版只能通过“快速重建 + 异地备份”降低恢复时间。
  • SpacetimeDB schema 回滚不一定可逆,必须把发布前备份作为强约束。
  • Jenkins controller 若在本地 Windowscontroller 自身备份和恢复需要单独制定,不应只依赖 agent 自恢复。
  • 外部模型网关失败可能影响创作能力,但不应影响已发布作品浏览和后台基础能力。

9.2 取舍

  • 选择先做可执行 runbook 和备份恢复演练,而不是直接引入复杂多活。
  • 选择继续复用现有 Jenkins 导入导出流水线,降低工程改造风险。
  • 选择不把密钥恢复细节写死到 Git 文档,避免泄露。

9.3 开放问题

  1. release 环境是否已经有独立备份机或对象存储?如果有,需要补充备份同步目标,但不能提交密钥。
  2. Jenkins controller 的 JENKINS_HOME 当前实际部署在哪里?是否已有周期备份?
  3. 生产域名 DNS TTL 当前是多少?是否可降低到适合故障切换的值?
  4. /stdb 所在磁盘是否独立于系统盘?是否已有磁盘水位告警?
  5. release 环境的通知渠道除邮件外是否需要接入企业微信/飞书/Telegram

10. 推荐实施顺序

  1. 先只落文档:技术方案 + runbook + 演练模板。
  2. 在 development 目标做一次数据库导出 + dry-run 导入演练。
  3. 根据演练结果补脚本:备份同步、备份健康检查。
  4. 再把 release 备份设置为定时任务。
  5. 最后规划整机重建演练与 DNS 切换演练。

首版完成标准:

  • 团队任一成员打开 runbook即可在 30 分钟内完成 Web/API 回滚或数据库备份 dry-run 恢复。
  • 最近一次数据库备份时间、备份位置、checksum、恢复演练结果可追溯。
  • 生产密钥仍只存在于服务器/Jenkins 凭据/加密备份中,不进入 Git。