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

448 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-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-<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
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 若在本地 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。