压测前置:指标口径、目标与验收标准
同一个接口,两拨人压出来的数字能差六倍:A 说「能扛 5000 QPS」,因为统计的是压测机发出的请求速率、而且缓存全命中;B 说「只有 800」,因为统计的是成功响应数、并且穿透到数据库。数字都没算错,口径不同而已。所以压测的第一步不是选工具,而是把每个指标的口径定义死,否则结论无法比较、无法复盘,也无法验收。
口径必须先定义清楚的东西
| 指标 | 分子 | 分母/窗口 | 必须说清的细节 |
|---|---|---|---|
| QPS(Queries Per Second) | 完成的请求数 | 1 秒窗口 | 统计「发出」还是「成功响应」?只算 200 还是含 4xx?多台压测机如何汇总? |
| 吞吐量(Throughput) | 处理的数据量或请求数 | 时间 | 看请求数还是字节数?是否含被限流丢弃的请求? |
| TPS(Transactions Per Second) | 完成的业务事务数 | 1 秒窗口 | 一个事务含几次下游调用?它与 QPS 的换算关系要写出来 |
| 延迟(Latency) | 单次请求耗时 | 采样分布 | 从哪算到哪:客户端发包到收完最后一个字节,还是服务端处理耗时?含不含 DNS、TLS、排队? |
| 分位数(Percentile) | P50/P95/P99/P999 | 同一时间窗口 | 分位数不能跨窗口平均,聚合要用直方图 |
| 错误率(Error Rate) | 失败请求数 | 总请求数 | 分母是「发出的」还是「完成的」?超时、连接失败、业务错误码算不算? |
| 并发数(Concurrency) | 同时在途的请求数 | 瞬时值 | 与连接数不是一回事,不同工具的 -c 含义不同 |
| 资源水位(Utilization) | 使用量 | 容量 | 被压机与压测机都要看:CPU、内存、GC、连接池、数据库 QPS、网络 |
最容易混的是并发数(Concurrency)与连接数(Connections):并发数指同一时刻在途的请求数,连接数是传输层复用后的通道数——HTTP/1.1 长连接下一个连接只能承载一个在途请求,HTTP/2 多路复用一个连接能承载几十条流。压测工具的 -c 各有所指:wrk 的 -c 是连接数,k6 的 vus 是虚拟用户数,ab 的 -c 是并发请求数,跨工具比较参数前必须先翻译口径。
用排队论反推并发数
并发数不该拍脑袋定,它由目标吞吐与延迟共同决定(利特尔法则,Little's Law):
在途并发 ≈ 目标 QPS × 平均响应时间
例:目标 2000 QPS,平均延迟 20ms → 并发 ≈ 2000 × 0.02 = 40
目标 2000 QPS,平均延迟 100ms → 并发 ≈ 2000 × 0.10 = 200
所以「用 200 并发压出 2000 QPS」和「用 40 并发压出 2000 QPS」不是同一个结论:前者说明系统已经在排队,后者说明还有余量。写方案时把「并发数 + 目标 QPS + 预期延迟」三者一起写,别人才能判断这组数字是否自洽。
为什么分位数不能平均
平均值会掩盖长尾:平均 50ms 而 P99 是 3s,意味着每 100 个请求里就有 1 个等了 3 秒。更容易犯错的是分位数的聚合方式——P99 不能求平均:
机器 A:P99 = 100ms,机器 B:P99 = 200ms
错误做法:(100 + 200) / 2 = 150ms ← 丢掉了各机请求量权重,没有意义
正确做法:合并两台机的延迟直方图后重算分位数(HdrHistogram / Prometheus histogram_quantile)
同理,多个时间段的分位数也不能平均。评估口径要统一成「同一窗口、同一采集方式、直方图聚合」。
验收标准怎么写
验收标准必须是可判定的句子,不能是「性能良好」「明显提升」。模板:
【负载模型】稳定负载 30 分钟,固定 200 并发(由目标 2000 QPS × 平均 100ms 推算),参数化取不重复 ID
【吞吐】成功响应 QPS ≥ 2000(1 秒窗口的 P5 不低于 1800,避免瞬时冲刺掩盖欠载)
【延迟】P99 ≤ 200ms,P95 ≤ 80ms,P50 ≤ 30ms(客户端口径,含网络与排队)
【错误率】< 0.1%,分母为总请求数;5xx、超时、连接失败均计入,业务错误码 1001(余额不足)不计入
【资源】被压机 CPU ≤ 70%、连接池使用率 ≤ 80%、无新增慢查询、内存无持续增长(30 分钟内斜率接近 0)
【稳定性】QPS 波动 < 10%,P99 无阶梯式上升,否则视为存在泄漏或性能退化
【有效性自检】压测机 CPU < 60%、网卡无丢包、无其他压测任务并行,否则本次结果作废
【前置条件】缓存预热完成、数据集 100 万行、依赖服务水位正常
句式记住这一条就够:「在 N 并发下,P99 ≤ X 毫秒、P95 ≤ Y 毫秒,成功 QPS ≥ Z,错误率 < 0.1%,被压机 CPU ≤ 70%」——每个数字都能对应一条采集口径,报告里的每个数字也能追溯到这条定义。
让 AI 帮你写前置章节
我要为「下单接口」做压测,只输出「指标口径」与「验收标准」两节,不要写脚本,也不要给结论。
要求:
1) 每个指标写成一行表格:指标名 | 分子 | 分母 | 统计窗口 | 含/不含什么 | 采集方式或指标名(如 Prometheus histogram_quantile);
2) 覆盖 QPS/TPS、P50/P95/P99、错误率、并发数与连接数的区别、CPU/内存/GC/连接池/数据库水位;
3) 验收标准用可判定句式:「在 <并发数> 并发下,P99 ≤ <P99_MS> ms,错误率 < <ERR_PCT>%,资源水位 ≤ <UTIL_PCT>%」,数值一律用占位符,不要自己编造;
4) 单列「需要我确认」的项,例如缓存是否预热、业务错误码是否计入错误率、数据集量级;
5) 最后回答:如果一方用「发出的请求数」当 QPS、另一方用「成功响应数」当 QPS,同一份报告会出现哪些互相矛盾的数字?
常见坑
| 坑 | 后果 | 规避 |
|---|---|---|
| 口径没定就开压 | 数字无法比较与验收,白压一轮 | 方案里先写口径表,评审通过后再压 |
| 只看平均值 | 长尾被掩盖,大客户先崩 | 以 P95/P99 为主指标,平均值只作参考 |
| 用并发数描述负载强度 | 跨工具不可比,结论无法迁移 | 用「并发 + 目标 QPS + 延迟」三元组描述 |
| 把 P99 直接平均 | 长尾被系统性低估 | 用直方图合并后重算分位数 |
| 错误率只算 5xx | 超时与连接失败被漏掉,假达标 | 明确分母与计入项,写进验收标准 |
| 忽略压测机水位 | 压测机先到瓶颈,被误判为服务端上限 | 压测机 CPU 与网卡同步监控,超线即作废 |
| 缓存状态不一致 | 未预热虚低,全命中虚高 | 报告里写清预热步骤与命中率 |
| 目标定成「越高越好」 | 没有通过线,无法判定 | 每条指标给出阈值与不达标时的处置 |
小结:压测的技术含量有一半在开压之前——先把 QPS/TPS、P50/P95/P99、错误率、并发数与连接数、资源水位的口径逐项定义死,用「并发 ≈ QPS × 平均延迟」校验负载模型是否自洽,再把验收标准写成「在 N 并发下 P99 ≤ X 毫秒、错误率 < 0.1%」这类可判定句式;口径统一之后,压测报告里的数字才能被比较、被复核,也才能支撑扩容或优化的决策。