# 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//` - `/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-export`、`jenkins/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 配置模板在 Git:`deploy/nginx/genarrative.conf`、`deploy/nginx/genarrative-dev-http.conf`。 - 为 release 环境建立 Nginx 配置备份与证书恢复流程。 - 明确 DNS 切换预案:生产机不可恢复时,将域名指向灾备机公网 IP。 2. **静态资源层:Web / Admin Web** - 依赖 `web.tar.gz`、`web.tar.gz.sha256`、`release-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:** ```bash 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---.json` - 增加 `SERVER_BACKUP_DIRECTORY` 默认建议: - `/var/backups/genarrative/spacetimedb//` - 增加备份保留策略: - 本机保留 7-14 天。 - 异地保留 30-90 天。 - 如实现 `production-backup-sync.sh`,只做同步框架,不硬编码真实 bucket、账号、endpoint 或密钥。 **Verification:** ```bash 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:** ```bash 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 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 文档与编码 ```bash npm run check:encoding ``` Expected: PASS。 ### 8.2 Shell 脚本语法 如新增 shell 脚本: ```bash 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 若在本地 Windows,controller 自身备份和恢复需要单独制定,不应只依赖 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。