16 KiB
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-ExportGenarrative-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。 - 数据回滚:使用导入流水线恢复指定备份,必须进入维护模式。
- Web 回滚:切
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 分层策略
-
入口层:Nginx / DNS / HTTPS
- 保留 Nginx 配置模板在 Git:
deploy/nginx/genarrative.conf、deploy/nginx/genarrative-dev-http.conf。 - 为 release 环境建立 Nginx 配置备份与证书恢复流程。
- 明确 DNS 切换预案:生产机不可恢复时,将域名指向灾备机公网 IP。
- 保留 Nginx 配置模板在 Git:
-
静态资源层:Web / Admin Web
- 依赖
web.tar.gz、web.tar.gz.sha256、release-manifest.json。 - 保留最近 N 个 release 目录与构建产物指针。
- 回滚只切软链,不重新构建。
- 依赖
-
API 服务层:Rust
api-server- 依赖归档的
api-server二进制、checksum、release-manifest.json。 /etc/genarrative/api-server.env通过加密备份或密钥管理恢复,不进入 release 包。- systemd unit 由
deploy/systemd/genarrative-api.service重新安装。
- 依赖归档的
-
数据层:SpacetimeDB
- 每次高风险发布前强制导出数据库。
- 定时导出:建议每天至少 1 次;高活跃期可每 4 小时 1 次。
- 导出产物同时保存在:Jenkins 归档 + 生产机
SERVER_BACKUP_DIRECTORY+ 异地对象存储/备份机。 - 导入前自动生成安全备份,保留当前实现口径。
-
发布编排层:Jenkins
- Jenkins Job、Jenkinsfile 在 Git 中可恢复。
- Jenkins controller 配置、凭据、插件清单需要额外备份。
- 发布 agent 使用 inbound + systemd 自恢复,agent secret 仅存在目标机或 Jenkins 凭据。
-
密钥与外部服务层
/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(只加稳定索引,不写敏感信息)
文档必须覆盖:
- 容灾目标:RTO/RPO 表。
- 生产资产清单:Nginx、systemd、release/current、
/stdb、/etc/genarrative/api-server.env、Jenkins、构建产物。 - 备份策略:
- 数据库导出。
- release 产物保留。
- Nginx/systemd/env 配置备份。
- Jenkins 配置备份。
- 恢复流程:
- Web 回滚。
- API 回滚。
- Stdb module 回滚。
- 数据恢复。
- 整机重建。
- 演练计划:每月一次数据库恢复演练,每季度一次整机重建演练。
- 安全边界:密钥不进 Git,备份加密,最小权限。
- 验收命令与人工检查清单。
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:
- 故障分级:P0/P1/P2。
- 第一响应:
- 判断 Nginx 是否在线。
- 判断
genarrative-api.service是否在线。 - 判断
spacetimedb.service是否在线。 - 判断磁盘是否满。
- 判断 Jenkins agent 是否在线。
- 快速止血:
- 开维护模式。
- 禁止继续发布。
- 保留现场日志。
- 回滚流程:
- Web 回滚命令。
- API 回滚命令。
- Stdb wasm 回滚命令。
- 数据恢复流程:
- 选择备份。
- dry-run 导入。
- 确认导入。
- smoke test。
- 整机重建流程:
- 新机器 provision。
- 恢复
/etc/genarrative/api-server.env。 - 恢复 SpacetimeDB 数据。
- 发布最近稳定 release。
- DNS 切换。
- 复盘模板。
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-Importdry-run 解析。 - 最近一次备份时间未超过 RPO 阈值。
- 导入后
/healthz可用。 - 首页、后台登录页、关键 API smoke 可用。
Verification:
bash -n scripts/deploy/verify-database-backup.sh
npm run check:encoding
Expected: PASS。
6. 具体恢复流程草案
6.1 Web 静态资源回滚
- 进入目标机。
- 查看 release 目录:
/opt/genarrative/releases/。 - 选择上一个稳定版本。
- 切换
/srv/genarrative/web或/opt/genarrative/current软链。 - 执行 Nginx 配置检查与 reload。
- 访问首页与后台静态入口。
验收:
/返回最新稳定页面。/admin/返回后台页面。- 静态资源无 404。
6.2 API 回滚
- 开维护模式。
- 切
/opt/genarrative/current到上一版包含稳定api-server的 release。 - 重启
genarrative-api.service。 - 本机检查
http://127.0.0.1:8082/healthz。 - 检查 Nginx 反代路径。
- 解除维护模式。
验收:
systemctl status genarrative-api.service正常。/healthz正常。- 后台
/admin/api/*基础接口正常。
6.3 SpacetimeDB 模块回滚
- 开维护模式。
- 确认目标数据库名与当前 API 环境一致:
GENARRATIVE_SPACETIME_DATABASE。 - 选择上一版
spacetime_module.wasm。 - 使用
spacetimedb服务用户发布上一版 wasm。 - 重启或检查
spacetimedb.service。 - 检查
api-server对目标数据库访问。 - 解除维护模式。
注意:如果 schema 已迁移且旧 wasm 不兼容当前数据,需要走数据恢复,不应直接盲目发布旧 wasm。
6.4 数据恢复
- 开维护模式。
- 从 Jenkins 归档或
SERVER_BACKUP_DIRECTORY选择备份。 - 先执行导入 dry-run。
- 真正导入前生成当前数据库安全备份。
- 执行导入。
- 执行 smoke test。
- 解除维护模式。
必须记录:
- 备份文件名。
- 来源 Job/build number。
- 恢复目标 database。
- 恢复开始/结束时间。
- 恢复后验证结果。
6.5 整机重建
- 准备新 Linux 机器。
- 接入 Jenkins release deploy agent,或准备人工 SSH 运维路径。
- 运行
Genarrative-Server-Provision:- 创建用户和目录。
- 安装 SpacetimeDB。
- 安装 systemd unit。
- 安装 Nginx 配置。
- 恢复
/etc/genarrative/api-server.env。 - 发布最近稳定 Web/API/Stdb 产物。
- 导入最近一次有效数据库备份。
- smoke test。
- 切 DNS。
- 观察 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-exportjenkins/Jenkinsfile.production-database-import
Expected: Pipeline syntax valid。
8.4 演练验收
至少完成一次 development 目标演练:
- 触发
Genarrative-Database-Export。 - 确认备份产物存在并归档。
- 使用
Genarrative-Database-Importdry-run 验证备份可解析。 - 不覆盖生产数据的前提下,记录演练报告。
release 目标演练应在业务低峰进行,并先确认通知渠道可用。
9. 风险、取舍与开放问题
9.1 风险
- 单机生产仍存在物理机级单点故障,首版只能通过“快速重建 + 异地备份”降低恢复时间。
- SpacetimeDB schema 回滚不一定可逆,必须把发布前备份作为强约束。
- Jenkins controller 若在本地 Windows,controller 自身备份和恢复需要单独制定,不应只依赖 agent 自恢复。
- 外部模型网关失败可能影响创作能力,但不应影响已发布作品浏览和后台基础能力。
9.2 取舍
- 选择先做可执行 runbook 和备份恢复演练,而不是直接引入复杂多活。
- 选择继续复用现有 Jenkins 导入导出流水线,降低工程改造风险。
- 选择不把密钥恢复细节写死到 Git 文档,避免泄露。
9.3 开放问题
- release 环境是否已经有独立备份机或对象存储?如果有,需要补充备份同步目标,但不能提交密钥。
- Jenkins controller 的
JENKINS_HOME当前实际部署在哪里?是否已有周期备份? - 生产域名 DNS TTL 当前是多少?是否可降低到适合故障切换的值?
/stdb所在磁盘是否独立于系统盘?是否已有磁盘水位告警?- release 环境的通知渠道除邮件外是否需要接入企业微信/飞书/Telegram?
10. 推荐实施顺序
- 先只落文档:技术方案 + runbook + 演练模板。
- 在 development 目标做一次数据库导出 + dry-run 导入演练。
- 根据演练结果补脚本:备份同步、备份健康检查。
- 再把 release 备份设置为定时任务。
- 最后规划整机重建演练与 DNS 切换演练。
首版完成标准:
- 团队任一成员打开 runbook,即可在 30 分钟内完成 Web/API 回滚或数据库备份 dry-run 恢复。
- 最近一次数据库备份时间、备份位置、checksum、恢复演练结果可追溯。
- 生产密钥仍只存在于服务器/Jenkins 凭据/加密备份中,不进入 Git。