# Chaos Engineering & Observability 设计

**作用**：详细设计文档。ADR 见 [decisions/2026-04-23-chaos-engineering-architecture.md](../decisions/2026-04-23-chaos-engineering-architecture.md)；实施进度见 [issues/archive/005-chaos-engineering-backup-migration.md](../issues/archive/005-chaos-engineering-backup-migration.md)。

## 目标

1. **防腐烂**（稀有事件演练）：备份恢复 / 机器迁移 / 数据整合等"半年才用一次"的运维动作——如果真要用时才发现脚本坏了、凭证过期了、流程有 gap，就是灾难。**定期自动演练 → 早发现**。

2. **防降级**（持续观测）：API 响应变慢、错误率抬升这些**悄悄的退化**——等用户反馈就晚了。**每日聚合指标 + 徽章可视化 → 一眼发现**。

业界叫法：Chaos Engineering（Netflix 首创 Chaos Monkey）+ Observability（Google SRE）。大厂标配 Prometheus + Grafana + Alertmanager + PagerDuty。我们两人团队用**轻量版**：GHA cron + 脚本 + GitHub status badges。

## 六个模块一览

| 代号 | 大白话一句 | workflow | 频率 | 徽章 |
|---|---|---|---|---|
| **M1** | 每小时问一次 OSS："昨天的备份还在吗" | `chaos-backup-freshness.yml` | hourly | [backup-fresh] |
| **M2** | 每天拉最新备份打开，"文件没坏吧" | `chaos-backup-integrity.yml` | daily | [backup-integrity] |
| **M3** | 每周在全新 GHA runner（异地）restore 一遍，"灾难恢复能救吗" | `chaos-restore-drill.yml` | weekly | [restore-drill] |
| **M4** | 每月真开按量 ECS，跑 provision+deploy 再销毁，"换机流程没生锈吧" | `chaos-migration-drill.yml` | monthly | [migration-drill] |
| **M5** | 每天算 24h API p50/p95/p99 + error rate，徽章红黄绿 | `chaos-metrics-daily.yml` | daily | [api-p95] [error-rate] |
| **M6** | 每月**真迁移**（backup → restore → 真数据 smoke），比 M4 多了数据 | `chaos-migration-full-drill.yml` | monthly (15 号) | [migration-full-drill] |

## 频率设计逻辑

为什么每个 M 这个节奏？**越重的演练频率越低**：

| 频率 | 演练成本 | 覆盖风险 |
|---|---|---|
| hourly | ~1 分钟 GHA runner，¥0 | cron 是否跑 / OSS 凭证是否过期 |
| daily | ~30s 计算，¥0 | 备份文件完整性 / schema 是否有效 |
| weekly | ~1 分钟 GHA runner 下载备份，¥0 | restore 链路是否可在异地跑 |
| monthly | ~15 分钟 + 真开 ECS，¥0.1-1 | 装机脚本是否能在全新机器跑通 |

**没选 hourly 开 ECS** —— 一年花 ¥100 验证一件每年才发生一次的事（换机），不值。

**没选 yearly** —— 一年发现挂了再修可能已经碰上真换机场景。

## 实现选型

### 为什么用 GHA cron 而不是 Prometheus / k8s cronjob / Airflow

| 方案 | 优点 | 缺点 |
|---|---|---|
| **GHA cron**（选这个）| 零成本 / 已有 infra / yaml + log 透明 / 失败有 GitHub UI 看 | cron 精度到分钟而非秒（够用）|
| Prometheus + Alertmanager | 业界标配 / 指标丰富 | 要 self-host 一套 / 两人团队运维负担大 |
| k8s CronJob | 云原生 | 我们没 k8s 集群，单独上一套不值 |
| airflow | 复杂调度强 | 大炮打蚊子 |

**核心判断**：两人团队 + 已经在用 GHA → 复用 GHA cron，资产共享。

### 为什么 M3 用 GHA runner 而不是 alpha 机器

M3 目的是模拟"**epsilon 整机 loss**"场景——如果 restore 脚本只能在**已经装好 xiangqin 的机器**上跑，真灾难（epsilon + alpha 一起挂）时就没法演练。

**GHA runner = 每次全新 Ubuntu，纯净环境**。装 aliyun CLI + sqlite → 从 OSS 拉 → 恢复 → 验证。这才证明 restore 链路**不依赖我们已有的任何机器**，是真·灾难恢复能力。

### 为什么 M4 用按量付费 ECS 而不是常驻机

**按量付费**：
- 每次演练 10-15 分钟 → ¥0.1-0.2/次
- 每月 1 次 → 年花费 ¥2 左右

**常驻**：
- 多一台小机器 ¥35-50/月 → 年花费 ¥420-600
- 还要维护（不演练时它也在那儿积尘）

**200 倍成本差，选按量**。

### 为什么 M6 独立于 M4 而不是合并

**职责分离**：
- M4 = "**装机流程**没腐"（单独验证 provision.sh 在新机跑通）
- M6 = "**整个迁移**没腐"（M4 + 真数据迁移 + smoke 验证）

为什么不直接把 M4 升级成 M6？因为：
- M4 每月跑一次，已经证明装机流程
- M6 多涉及 OSS 读 + sqlite 文件操作，链路更长失败面更大
- 如果合并，M4 挂了分不清是"装机挂了"还是"数据迁移挂了"
- **失败信号分离 → debug 快**

### 为什么 M5 用 `metrics-data` 孤儿分支而不是 commit main

每日 workflow 写徽章 JSON → 如果 commit 到 main，每天一个 "metrics update YYYY-MM-DD" commit 污染历史 + 触发 CI 跑一圈（浪费 GHA minutes + CF Pages 重新 build）。

**孤儿分支（`git checkout --orphan`）**：
- 每日 force-push 只影响 `metrics-data` 分支
- `main` 历史干净
- shields.io 通过 raw GitHub URL 从 `metrics-data` 分支读 JSON
- **业界实践**：Netflix / Google 等用的 gh-pages 分支模式，这里借用

## 观测 & 反馈

### 徽章（README 顶部一排）

- 绿 = 上次跑成功（"目前没腐"）
- 红 = 上次跑失败（"有东西腐了，去看日志"）
- 黄 = 降级（M5 p95 > 300ms 等阈值）

### 失败通知

**当前**：GHA 会自动发邮件给 owner（yarnovo@）当 workflow failure。

**未来可加**：
- Telegram / Slack webhook（webhook url 进 vault）
- SMS（走 aliyun SMS，但成本高）
- GitHub issue 自动创建（GHA action 支持）

### 徽章颜色阈值（M5）

| 指标 | 绿 | 黄 | 红 |
|---|---|---|---|
| api p95 | < 100ms | 100-1000ms | > 1000ms |
| error rate | < 0.1% | 0.1-1% | > 1% |

## 未来扩展（不做或 v0.5+）

### M7: Performance regression alert

当 M5 p95 连续 3 天上升超过阈值（e.g. +50%）→ 发报警。需要存历史指标 + 对比。

### M8: Alert-test drill

故意让 M1 fail（比如改脚本让它认为备份 100h 前）→ 验证报警链路。**"演练演练本身"**，元一层。

### M9: Replication lag check（Postgres 时代）

等 xiangqin v0.5+ 迁 Postgres 主从复制后，加 workflow 监控主从 lag。

### M10: Security scan drill

定期扫依赖 CVE（`uv pip audit`）+ SKILL.md 是否泄露敏感词（之前发生过 vault 段泄露）。

## 维护

- **每月 review**：徽章墙是否全绿？失败 workflow 是否修了？频率是否合适？
- **改 workflow** 时**同步更新本 doc**（workflow 改了 doc 没改 = 腐烂）
- **增加 M 时**加 issue → blueprint 补一段 → ADR 记里程碑
