topfans/backend/scripts/loadgen/scripts/README.md
2026-06-16 23:00:07 +08:00

170 lines
5.5 KiB
Markdown

# scripts/ — 部署到生产机的辅助脚本
> 这些脚本不需要在生产机上跑。`prod_loadtest.sh` 是一站式包装,
> 把所有 SSH 隧道、seed、loadgen、preflight、report、cleanup 操作
> 串成子命令,本地直接调,目标始终是生产 DB / 生产网关。
---
## 📜 脚本清单
| 脚本 | 用途 | 谁要跑 |
|------|------|--------|
| **[prod_loadtest.sh](prod_loadtest.sh)** | 一站式压测:子命令模式 (`up` / `seed` / `loadgen` / `report` / `cleanup-all` / `pipeline` 等) | on-call、想跑压测的工程师 |
| [prod_seed.sh](prod_seed.sh) | ⚠️ 旧脚本:只能在生产机上跑 (SSH 进去后 `bash prod_seed.sh`) | 不推荐使用,统一改用 prod_loadtest.sh |
| [mint_reset.sh](mint_reset.sh) | mint 数据重置(每跑完一个 S4 stage 调一次) | loadgen S4 场景内部调用,不用手跑 |
---
## 🚀 快速开始 (prod_loadtest.sh)
### 一键完成整个压测流程
```bash
cd /Users/liulujian/Documents/code/TopFansByGithub
# 一键:up → backup → seed → preflight → loadgen → report → cleanup-all → down
./backend/scripts/loadgen/scripts/prod_loadtest.sh pipeline \
--scenarios=S1,S2,S4 \
--stage=step --step-schedule='5,10,20' \
--duration=60s
```
### 细粒度控制(推荐)
```bash
SCRIPT=./backend/scripts/loadgen/scripts/prod_loadtest.sh
# 1. 建 SSH 隧道
$SCRIPT up
# 2. 备份生产 DB
$SCRIPT backup
# 3. 灌 1000 测试用户 + 23k 行数据
$SCRIPT seed
# 4. 开压前 7 项检查
$SCRIPT preflight
# 5. 跑压测 (所有 loadgen 参数透传)
$SCRIPT loadgen \
--scenarios=S1,S2,S4 \
--stage=step --step-schedule='5,10,20' \
--duration=60s
# 6. 生成 final-report.md
$SCRIPT report
# 7. 全清压测数据 (含 users + stars,序列同步)
$SCRIPT cleanup-all
# 8. 关隧道
$SCRIPT down
```
### 查看状态(任何时候)
```bash
$SCRIPT status
# == SSH 隧道 ==
# ✅ 本地 25432 端口转发在跑 (PID: 12345)
# == 生产 DB 容器 ==
# topfans-postgres Up 22 hours (healthy) 0.0.0.0:5432->5432/tcp
# == 最近 3 次备份 ==
# pre-loadtest-20260616-2151.sql 1.2M
# == 本地 reports/ ==
# S1.json / S2.json / S4.json / final-report.md
```
---
## 📋 子命令速查
| 子命令 | 说明 | 副作用 |
|--------|------|--------|
| `up` | 建 SSH 隧道 `本地 25432 → 生产 5432` | 启动 `ssh -f -N -L 25432:...` |
| `down` | 关 SSH 隧道 | 杀掉 ssh 进程 |
| `status` | 隧道/容器/备份/reports 状态 | 只读 |
| `backup` | 备份生产 DB → `/opt/topfans/backups/pre-loadtest-<ts>.sql` | 写生产机磁盘 |
| `seed` | 灌 1000 users + 23k 行 (通过隧道写生产 DB) | 写生产 DB |
| `preflight` | 7 项开压前检查 | 只读 |
| `loadgen [args]` | 跑压测,所有参数透传给 `./bin/loadgen --cmd=run` | 打生产网关 + 写 reports/ |
| `report` | 把 reports/ 下的 S*.json 合成 final-report.md | 写 reports/final-report.md |
| `cleanup` | 清理压测数据(**保留** users + stars) | 写生产 DB(删 rows) |
| `cleanup-all` | 全清(**含** users + stars,序列同步重置) | 写生产 DB(删 rows + setval) |
| `pipeline [args]` | `up → backup → seed → preflight → loadgen → report → cleanup-all → down` | 一条龙,loadgen args 透传 |
---
## 🔧 环境变量(可选覆盖)
```bash
PROD_HOST=root@101.132.250.62 # 默认
TUNNEL_PORT=25432 # 默认
BACKEND_DIR=... # 默认脚本所在目录的 ../../..
```
例:测不同端口:
```bash
TUNNEL_PORT=35432 $SCRIPT up
TUNNEL_PORT=35432 $SCRIPT seed
```
---
## 🛡️ 设计要点
### 1. SSH 端口转发为啥必要?
- 生产机 `topfans-postgres` 容器是 PostgreSQL **18.3**
- 本地 `pg_dump`**17.4** → 版本不兼容
- 解决:seed/cleanup 走 `docker exec topfans-postgres pg_dump` 容器内跑 (版本匹配)
- `prod_loadtest.sh` 把这个细节封装在 `seed` / `cleanup` / `cleanup-all`
### 2. 凭据从哪来?
- 所有子命令从 `docker/.env.prod``DB_PASSWORD` / `JWT_SECRET`
- 不在命令行明文泄露
- 调用方看不到 .env.prod 文件(只要 prod_loadtest.sh 内部读)
### 3. 数据安全
- `--cleanup`(默认):保留 1000 users,只清资产(支持"多轮压测")
- `--cleanup-all`:**含** users + stars(适合"压测彻底收尾")
- 序列同步:cleanup 末尾会 `setval()` 所有相关表的 sequence(避免后续 GORM 报 duplicate key)
### 4. 为什么不用 prod_seed.sh?
- `prod_seed.sh` 需要 SSH 到生产机跑,**有歧义**(以为是 prod-only 工具)
- `prod_loadtest.sh` 全部在本地,**语义清晰**(本地调,目标生产)
- 保留 `prod_seed.sh` 是为了向后兼容(已经在生产机上跑过的人),但 README/工具集都优先推荐 `prod_loadtest.sh`
---
## 🔍 故障排查
### "本地 25432 端口未监听"
`$SCRIPT up` 建隧道。
### "DB_PASSWORD 未找到"
检查 `docker/.env.prod` 是否存在并有 `DB_PASSWORD=` 行。
### preflight ③ backup 报 < 50MB
生产库本身小(几十 MB),RUNBOOK 红线是历史经验值,不是阻断错误。
### loadgen 报 `circuit breaker tripped!`
`loadgen-*.log``🚨 circuit breaker tripped!` 上下文:
- 如果错误率/p99 正常,可能是 `metrics-feed.jsonl` 缺失导致误 trip(已修复:`latestServer` 改 nil 判断)
- 如果是真有错,看报告里 `S*.json``errors` 字段
### SSH 隧道被挂起或断
```bash
$SCRIPT down
$SCRIPT up
```
---
## 📂 相关文件
- 上层: [../README.md](../README.md) | [../RUNBOOK.md](../RUNBOOK.md) | [../REPORT_GUIDE.md](../REPORT_GUIDE.md)
- seed 工具: [../seed/README.md](../seed/README.md)
- reports 输出: [../../reports/](../../reports/) (gitignore)