267 lines
8.2 KiB
Markdown
267 lines
8.2 KiB
Markdown
# REPORT_GUIDE — 压测报告怎么读
|
||
|
||
> **目标读者**:看完压测报告后,需要判断"系统能扛住吗"+"哪里是瓶颈"+"下一步改什么"的工程师
|
||
> **报告路径**:`reports/final-report.md` (主) + `reports/{scenario}.json` (原始) + `reports/{scenario}.png` (图)
|
||
|
||
---
|
||
|
||
## 1. 报告目录结构
|
||
|
||
```
|
||
reports/
|
||
├── S1.json # 场景 1 原始数据 (程序读)
|
||
├── S2.json # 场景 2
|
||
├── S4.json # 场景 4
|
||
├── baseline.csv # Excel 可打开的汇总表
|
||
├── s1.png # 场景 1 曲线图 (RPS / P99 / Error)
|
||
├── s2.png
|
||
├── s4.png
|
||
└── final-report.md # ← 你要看的总报告
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 三步读完报告
|
||
|
||
### 第 1 步:看汇总表 (1 分钟)
|
||
|
||
```markdown
|
||
| Scenario | Total | Err | 5xx | P50ms | P95ms | P99ms | Maxms | Stages |
|
||
|----------|-------|-----|-----|-------|-------|-------|-------|--------|
|
||
| S1 | 12500 | 0 | 0 | 86.59 | 119.23 | 200.50 | 450 | 5 |
|
||
| S2 | 25000 | 5 | 0 | 12.30 | 35.00 | 88.00 | 250 | 5 |
|
||
| S4 | 600 | 12 | 2 | 200.00 | 500.00 | 850.00 | 1200 | 4 |
|
||
```
|
||
|
||
**每个字段的含义**:
|
||
|
||
| 字段 | 含义 | 健康参考 (4G/2C prod) |
|
||
|------|------|----------------------|
|
||
| `Scenario` | 场景 ID (S1=登录, S2=读, S3=点赞, S4=铸造, ...) | — |
|
||
| `Total` | 该场景总请求数 | 越大越好,代表你扛住了 |
|
||
| `Err` | 客户端+服务端错误总和 | **< 1%** |
|
||
| `5xx` | 服务端错误 (500-599) | **< 0.1%** (1‰) |
|
||
| `P50ms` | 50% 请求在这个时间内 | < 100ms |
|
||
| `P95ms` | 95% 请求在这个时间内 | < 300ms |
|
||
| `P99ms` | 99% 请求在这个时间内 | < 1000ms (S4 写重可放宽到 2000ms) |
|
||
| `Maxms` | 最慢的一次请求 | 一般 3-5x P99 |
|
||
| `Stages` | 阶梯测试的阶段数 | = step-schedule 的元素数 |
|
||
|
||
**判断模板**:
|
||
- ✅ 全绿 → 系统扛得住,准备上线
|
||
- ⚠️ 某个 S* Err > 1% → 优先看那个场景
|
||
- 🚨 某个 S* 5xx > 1% → 服务端有问题,看 §3 定位
|
||
|
||
---
|
||
|
||
### 第 2 步:看拐点 (KneeRPS) (2 分钟)
|
||
|
||
每个 scenario 标题下会出现一行:
|
||
|
||
```markdown
|
||
**⚠️ 拐点**: stage 3 @ 3 RPS (p99 暴涨 514%)
|
||
```
|
||
|
||
**含义**: 当 RPS 升到 3 时,p99 延迟比 stage 2 暴涨 514% (5.14 倍)。
|
||
|
||
**判定逻辑** (在 `reporter/knee.go`):
|
||
- 逐 stage 比 p99
|
||
- 第一次涨幅 > 50% 时,标记为拐点
|
||
- 全程没涨 > 50% → 显示 "✅ 拐点未触发"
|
||
|
||
**怎么用这个数字**:
|
||
- **S1 拐点 RPS = 15** → 你的登录服务,超过 15 QPS 就开始劣化。生产预估峰值 10 QPS,留 50% buffer
|
||
- **S4 拐点 RPS = 2** → 铸造接口很重,2 QPS 就劣化了。要么优化,要么限流
|
||
|
||
**举例**:
|
||
| 拐点 RPS | 业务含义 | 行动项 |
|
||
|---------|---------|--------|
|
||
| ≥ 期望峰值的 2x | ✅ 健康 | 上线,加监控 |
|
||
| ≈ 期望峰值 | ⚠️ 临界 | 加缓存 / 异步化 / 限流 |
|
||
| < 期望峰值 | 🚨 不达标 | 重构 + 复测 |
|
||
|
||
---
|
||
|
||
### 第 3 步:看阶梯表 + 曲线图 (5 分钟)
|
||
|
||
**阶梯表** (md 里每个场景下):
|
||
|
||
```markdown
|
||
### 阶梯结果
|
||
| Stage | TargetRPS | Total | Err | 5xx | P50ms | P95ms | P99ms | Maxms |
|
||
|-------|-----------|-------|-----|-----|-------|-------|-------|-------|
|
||
| 1 | 2 | 600 | 0 | 0 | 80 | 100 | 110 | 130 |
|
||
| 2 | 5 | 1500 | 0 | 0 | 82 | 105 | 115 | 140 |
|
||
| 3 | 10 | 3000 | 0 | 0 | 85 | 110 | 130 | 180 |
|
||
| 4 | 15 | 4500 | 0 | 0 | 95 | 130 | 200 | 350 |
|
||
| 5 | 20 | 6000 | 5 | 0 | 120 | 200 | 450 | 800 |
|
||
```
|
||
|
||
**怎么读**:
|
||
|
||
- **Total** 应该是 `TargetRPS × Duration` (近似,因为有误差)
|
||
- **P99ms** 应该随 TargetRPS 上升**平滑增加** (10-30% 涨幅/stage 是正常)
|
||
- **Err / 5xx** 应该全程 < 1%
|
||
- **如果某 stage 突然 P99 翻倍** → 拐点,看上面 KneeRPS
|
||
|
||
**曲线图** (`s1.png` 等):
|
||
|
||
- **X 轴**: Stage 编号 (1, 2, 3, ...)
|
||
- **Y 轴**: 三个值 — RPS (蓝)、P99ms (绿)、Error% (红)
|
||
- **怎么看**:
|
||
- 三条线**平稳上升** = 正常
|
||
- **P99 突然陡升** = 拐点
|
||
- **Error% 突然跳起来** = 服务挂了
|
||
|
||
---
|
||
|
||
## 3. 定位瓶颈 — 常见模式
|
||
|
||
### 模式 1: P99 阶梯上升,但 Error 一直 0
|
||
**含义**: 系统扛得住,但在变慢。
|
||
**原因**: GC 抖动 / DB 慢查询 / 锁竞争。
|
||
**行动**:
|
||
1. 看 PG 慢查询日志: `pg_stat_statements` ORDER BY `mean_exec_time` DESC
|
||
2. 看应用层 profile: `pprof` heap + cpu
|
||
3. 检查连接池配置: 可能太小
|
||
|
||
### 模式 2: P99 阶梯上升 + Error 也开始涨
|
||
**含义**: 系统到极限。
|
||
**原因**: 资源耗尽 (CPU 100%, 连接池满, DB 锁)。
|
||
**行动**:
|
||
1. 看 server metrics feed: `tail -f metrics-feed.jsonl`
|
||
2. `top` 看 CPU/内存,`iostat` 看 IO
|
||
3. 检查是否有连接泄漏 (`netstat | grep TIME_WAIT`)
|
||
|
||
### 模式 3: 阶梯早期就 5xx > 5%
|
||
**含义**: 系统本身有问题,不是负载问题。
|
||
**原因**: 代码 bug / 配置错误 / 依赖缺失。
|
||
**行动**:
|
||
1. 看 5xx 的具体响应体 (在 log 里)
|
||
2. 检查 error 码,对照业务错误码定义
|
||
3. 看是不是 auth/JWT 过期
|
||
|
||
### 模式 4: 第一个 stage P99 很高,后续反而低
|
||
**含义**: 热身不够 / 缓存没预热。
|
||
**原因**: Redis 冷启动 / JIT 编译 / DB 连接池启动慢。
|
||
**行动**:
|
||
1. 第一次 stage 加长 (例如先 2min 预热)
|
||
2. 或者用 `--rps=1` 先跑 1-2min 预热,再开阶梯
|
||
|
||
### 模式 5: S4 (Mint) 在很低的 RPS 就拐
|
||
**含义**: 写路径太重。
|
||
**原因**: 铸造涉及事务 / 签名 / OSS 上传,本身就是慢操作。
|
||
**行动**:
|
||
1. 检查 mint 是不是同步阻塞 (能不能异步化?)
|
||
2. 看 mint 数据是否需要落库 (能否用 append-only?)
|
||
3. 考虑限流: 服务端拒绝 > 2 QPS 的 mint 请求
|
||
|
||
---
|
||
|
||
## 4. 怎么写出行动项
|
||
|
||
读完报告,应该能回答三个问题:
|
||
|
||
### Q1: 系统能扛住业务预期峰值吗?
|
||
- 业务预期峰值 → 比对拐点 RPS
|
||
- 拐点 ≥ 2x 峰值 → ✅ 可以上线
|
||
- 拐点 ≈ 1x 峰值 → ⚠️ 加监控告警,谨慎上线
|
||
- 拐点 < 峰值 → 🚨 必须先优化
|
||
|
||
### Q2: 拐点在哪里?为什么?
|
||
看哪个 stage 拐的,然后:
|
||
- **CPU 100%** → 计算密集,优化算法或加机器
|
||
- **DB CPU 100%** → 慢查询,加索引或读写分离
|
||
- **PG 连接数满** → 连接池配置 / 服务降级
|
||
- **PG 锁等待** → 事务设计问题
|
||
- **磁盘 IO 满** → 加 SSD 或缓存
|
||
|
||
### Q3: 下一步改什么?
|
||
|
||
行动项模板:
|
||
|
||
```markdown
|
||
## [Loadtest 2026-06-15] 行动项
|
||
|
||
### P0 (上线前必修)
|
||
- [ ] **S2 Read 拐点 100 RPS < 业务预期 150 RPS**
|
||
- 根因: PG `assets` 表全表扫描,10 万行
|
||
- 修复: 加 `idx_assets_star_id_status` 索引
|
||
- Owner: @dba
|
||
|
||
### P1 (1 周内修)
|
||
- [ ] **S4 Mint 拐点 2 RPS**
|
||
- 根因: 同步写 OSS + 同步落库
|
||
- 修复: mint 流程拆成 precreate + 后台 worker
|
||
- Owner: @backend
|
||
|
||
### P2 (技术债)
|
||
- [ ] 压测期间 CPU 持续 80%,考虑扩容到 4C
|
||
```
|
||
|
||
---
|
||
|
||
## 5. JSON 原始数据怎么读 (高级)
|
||
|
||
`reports/S1.json` 长这样:
|
||
|
||
```json
|
||
{
|
||
"scenario": "S1",
|
||
"total_requests": 12500,
|
||
"errors": 5,
|
||
"five_xx": 0,
|
||
"p50_us": 86591,
|
||
"p95_us": 119231,
|
||
"p99_us": 200502,
|
||
"max_us": 450000,
|
||
"stages": [
|
||
{
|
||
"stage_idx": 1,
|
||
"target_rps": 2,
|
||
"total_requests": 600,
|
||
"errors": 0,
|
||
"five_xx": 0,
|
||
"p50_us": 80000,
|
||
"p95_us": 100000,
|
||
"p99_us": 110000,
|
||
"max_us": 130000
|
||
},
|
||
...
|
||
]
|
||
}
|
||
```
|
||
|
||
**单位说明**:
|
||
- 所有 `_us` 后缀 = microseconds (微秒,1ms = 1000us)
|
||
- 例: `p99_us: 200502` = 200.5 ms
|
||
|
||
**怎么用**:
|
||
- 画自己的图 (用 Excel/Google Sheets 打开 baseline.csv 最方便)
|
||
- 跟历史报告对比 (跨版本性能回归)
|
||
- CI 集成: 解析 JSON,断言 P99 < 某个阈值
|
||
|
||
---
|
||
|
||
## 6. 常见问题
|
||
|
||
### Q: "5xx=0 但 Err=5" 是什么意思?
|
||
A: 5xx 是服务端错,Err 是总错 (含 4xx)。Err > 5xx 表示有客户端错 (一般是 401/403/404)。看 log 里具体错误码。
|
||
|
||
### Q: 为什么 P50 很低但 P99 很高?
|
||
A: 正常 — 长尾效应。99% 都快但 1% 慢。如果 P99 太高说明有少数请求卡住,看是不是 GC / 锁 / IO 抖动。
|
||
|
||
### Q: Max 比 P99 高很多,是不是异常?
|
||
A: 可能是单个网络抖动,正常。Max / P99 < 5x 都是健康。
|
||
|
||
### Q: 同一个场景不同次跑,数据差很多?
|
||
A: 检查 prod 是否有其他流量在跑 (业务)。压测应在凌晨,业务低峰。
|
||
|
||
---
|
||
|
||
## 7. 进一步
|
||
|
||
- 想优化场景,见 `seed/README.md`
|
||
- 想加新场景,在 `scenarios/` 新建 `s8_xxx.go`,模仿 s1_login.go 的 BeginStage/EndStage 模式
|
||
- 想加新的红线指标,见 `lib/circuit.go`
|