# 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`