topfans/backend/scripts/loadgen/REPORT_GUIDE.md
2026-06-15 20:10:56 +08:00

8.2 KiB
Raw Blame History

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 分钟)

| 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 标题下会出现一行:

**⚠️ 拐点**: 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 里每个场景下):

### 阶梯结果
| 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: 下一步改什么?

行动项模板:

## [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 长这样:

{
  "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