feat: build legacy practice navigation

This commit is contained in:
Codex
2026-06-30 12:47:27 +08:00
parent fce5513464
commit d005f65fe7
12 changed files with 2460 additions and 11 deletions

View File

@@ -0,0 +1,154 @@
# API 压测与 4 核 16G 容量评估 Runbook
更新时间2026-06-30
这份 runbook 用于在本地 Docker/Supabase 或未来 4 核 16G 云服务器上,对 SaaS 题库 API 做可重复压测。目标不是一次性给出永久容量承诺而是建立一套可以随着题库、用户量、SQL 和硬件变化持续复跑的基线。
## 工具
压测脚本:
```bash
npm run perf:api:local
```
脚本会:
- 自动从 `DATABASE_URL` 指向的 PostgreSQL 中发现一个活跃租户、学生、题库入口、分类节点、合集、练习蓝图、单词单元和知识手册。
- 默认启动本地 API 服务,并使用真实 API 请求做混合读路径压测。
- 默认不创建练习 session不写业务数据。
- 输出 JSON 和 Markdown 报告到 `docs/refactor/performance-reports/`。该目录已被 `.gitignore` 忽略,不应提交。
## 前置条件
本地真实迁移库压测:
```powershell
npx supabase db reset
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
npm run pb:import:json
npm run pb:import:validate
npm run perf:api:local
```
烟测 seed 压测:
```powershell
$env:DATABASE_URL="postgresql://postgres:postgres@127.0.0.1:54322/postgres"
npm run db:smoke-seed
npm run perf:api:local
```
如果 API 已经在运行:
```powershell
$env:PERF_START_SERVER="false"
$env:PERF_API_BASE="http://127.0.0.1:8787"
npm run perf:api:local
```
## 环境变量
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `DATABASE_URL` | `postgresql://postgres:postgres@127.0.0.1:54322/postgres` | 压测使用的数据源 |
| `PERF_API_BASE` | 空 | 已运行 API 地址;为空时默认启动本地 API |
| `PERF_START_SERVER` | 根据 `PERF_API_BASE` 推断 | 是否由脚本启动 API |
| `PERF_API_PORT` | 随机端口 | 脚本启动 API 时使用的端口 |
| `PERF_TENANT_CODE` | `master` | 优先选择的租户 slug |
| `PERF_DURATION_SECONDS` | `15` | 压测持续时间 |
| `PERF_CONCURRENCY` | `6` | 并发 worker 数 |
| `PERF_RAMP_SECONDS` | `3` | 并发爬坡时间 |
| `PERF_QUESTION_LIMIT` | `20` | 单次合集题目请求数量 |
| `PERF_INCLUDE_WRITES` | `false` | 是否加入创建练习 session 写请求 |
| `PERF_OUTPUT_DIR` | `docs/refactor/performance-reports` | 报告输出目录 |
| `PERF_REQUEST_TIMEOUT_MS` | `15000` | 单请求超时 |
## 默认工作负载
默认混合读路径包含:
- `/health`
- `/api/tenant/resolve`
- `/api/catalog/regions`
- `/api/catalog/content-entries`
- `/api/catalog/content-nodes?mode=flat`
- `/api/catalog/question-collections`
- `/api/catalog/question-collections/questions`
- `/api/catalog/practice-blueprints`
- `/api/learning/stats`
- `/api/learning/trend`
- `/api/learning/leaderboard`
- `/api/catalog/vocabulary-words`
- `/api/learning/vocabulary/stats`
- `/api/catalog/handbook-chapters`
- `/api/catalog/handbook-entries?includeContent=true`
写入路径默认关闭。只有在专门的测试库或可丢弃预生产库中,才建议打开:
```powershell
$env:PERF_INCLUDE_WRITES="true"
npm run perf:api:local
```
开启后会加入低权重 `POST /api/learning/practice-sessions`,用于观察组卷、免费额度、权益校验和 session 写入开销。
## 4 核 16G 阶梯压测建议
在云服务器上先按 `docs/refactor/postgresql-4c16g-tuning.md` 配置 shared-host 起步值,再跑以下矩阵。每轮之间间隔 2 到 5 分钟,观察 CPU、内存、磁盘 I/O、连接数和慢 SQL。
| 场景 | 并发 | 时长 | 写入 | 用途 |
| --- | ---: | ---: | --- | --- |
| smoke | 6 | 30s | 否 | 确认部署和数据可访问 |
| baseline-10 | 10 | 2min | 否 | 学生正常浏览/刷题入口 |
| baseline-30 | 30 | 5min | 否 | 中小租户晚高峰 |
| baseline-50 | 50 | 5min | 否 | 单机读路径压力观察 |
| mixed-30 | 30 | 5min | 是 | 加入少量创建练习 session |
| mixed-50 | 50 | 5min | 是 | 观察写入、锁和连接池 |
| spike-100 | 100 | 2min | 否 | 短峰值和缓存命中观察 |
PowerShell 示例:
```powershell
$env:DATABASE_URL="postgresql://postgres:***@127.0.0.1:5432/postgres"
$env:PERF_API_BASE="https://api.example.com"
$env:PERF_START_SERVER="false"
$env:PERF_DURATION_SECONDS="300"
$env:PERF_CONCURRENCY="30"
$env:PERF_RAMP_SECONDS="30"
$env:PERF_INCLUDE_WRITES="false"
npm run perf:api:local
```
## 初步验收线
上云测试早期建议先用保守指标:
- 只读 mixed catalog 工作负载P95 小于 300msP99 小于 800ms错误率小于 0.1%。
- 加入少量 session 写入P95 小于 500msP99 小于 1200ms错误率小于 0.5%。
- 数据库无连接耗尽、无 OOM、无长时间 `idle in transaction`
- `pg_stat_database``xact_rollback` 不应快速增长。
- `pg_stat_activity` 不应长期堆积锁等待或 I/O wait。
这些不是最终 SLA。正式 SLA 要结合真实云服务器、真实 CDN、真实对象存储、真实支付回调和前端 Web Vitals 重新制定。
## 问题定位
如果 P95 或 P99 明显升高,按下面顺序排查:
1. 查看报告的接口明细,先定位慢接口。
2. 打开 PostgreSQL 慢 SQL 日志,或在生产启用 `pg_stat_statements`
3. 对慢接口涉及 SQL 执行 `explain (analyze, buffers)`
4. 检查 API/worker 连接池是否过大导致数据库活跃连接超过 4 核可承受范围。
5. 检查 `content_nodes path``question_collection_items``answer_records``practice_sessions``vocabulary_progress` 等大表索引。
6. 对 dashboard、排行榜、销售转化、分佣报表这类聚合接口优先做日/小时预聚合,而不是无限放大 SQL 超时。
## 结果归档
本地生成的报告目录不入 Git。正式上云验收时可以把代表性结果摘要写入 `production-launch-evidence.json` 的本地证据文件,再运行:
```bash
npm run launch:gate
```
证据中只记录报告路径、并发矩阵、P95/P99、错误率和结论不保存真实 token、支付密钥、用户隐私或完整响应。