2. 性能度量与基准测试:关键性能指标与实战方法论
性能优化这件事,说白了就是「先测量,再优化」。没有度量,就没有改进。我见过太多团队一上来就闷头改代码,改完发现性能反而更差了——为什么?因为连瓶颈在哪都没搞清楚。
这一章,我们来聊聊性能度量那些事。我会结合自己踩过的坑,把延迟、吞吐量、QPS、TP99这些指标讲透,再聊聊基准测试到底该怎么做。
2.1 关键性能指标:你到底该关注什么?
性能指标有很多,但真正关键的其实就几个。我个人习惯把指标分成两类:速度类和容量类。
2.1.1 延迟(Latency)
延迟,就是一次请求从发出到收到响应所花的时间。单位通常是毫秒(ms)或微秒(μs)。
你想想看,用户点一个按钮,等多久会不耐烦?我做过一个电商项目,首页加载从 2 秒优化到 0.8 秒,转化率直接提升了 12%。这就是延迟的威力。
2.1.2 吞吐量(Throughput)
吞吐量是系统在单位时间内能处理的请求数量。常见单位有:
- RPS(Requests Per Second):每秒请求数
- TPS(Transactions Per Second):每秒事务数
- QPS(Queries Per Second):每秒查询数
这三个概念经常混用,但严格来说,TPS 包含一个完整的事务(可能涉及多次查询),而 QPS 只算单次查询。我在项目中一般用 QPS 来衡量 API 网关,用 TPS 来衡量数据库写入。
2.1.3 QPS 与 TP99
QPS 很好理解,就是每秒能扛多少请求。但 TP99 是什么?
TP99(Top Percentile 99)意思是:99% 的请求延迟都在这个值以下。举个例子,TP99 = 200ms,说明只有 1% 的请求会超过 200ms。
为什么要关注 TP99?因为平均值会骗人。我曾经遇到一个系统,平均延迟只有 50ms,但 TP99 高达 2 秒。这意味着每 100 个用户里就有 1 个在「吃屎」——用户体验极差。
| 指标 | 含义 | 典型值 | 关注点 |
|---|---|---|---|
| 平均延迟 | 所有请求延迟的算术平均 | 50ms | 容易被极端值拉偏 |
| TP50 | 50% 请求的延迟上限 | 30ms | 反映大多数用户感受 |
| TP99 | 99% 请求的延迟上限 | 200ms | 反映长尾问题 |
| TP999 | 99.9% 请求的延迟上限 | 1s | 极端情况下的体验 |
2.2 基准测试方法论:别让测试结果骗了你
基准测试(Benchmark)就是给系统「称体重」。但称体重也有讲究——你站错秤、穿错鞋,结果都不准。
2.2.1 测试环境要隔离
这个坑我踩过。有一次我在开发环境做压测,结果发现 QPS 死活上不去。折腾了半天,才发现隔壁团队正在跑一个大数据任务,把 CPU 吃满了。
所以,基准测试一定要在隔离环境中进行:
- 专用机器,不混部
- 关闭不必要的后台进程
- 网络带宽要充足
- 监控系统本身的开销要扣除
2.2.2 预热(Warm-up)必不可少
JVM 有 JIT 编译,数据库有缓存,连接池有初始化。如果不预热,你测出来的其实是「冷启动性能」,不是真实性能。
我一般会先跑 1-2 分钟的预热请求,等指标稳定了再开始记录数据。
2.2.3 测试时长要足够
跑 10 秒就下结论?太草率了。我建议:
- 最少跑 3 分钟
- 观察是否有 GC 抖动
- 观察是否有连接泄漏
- 多次测试取中位数
2.2.4 控制变量法
一次只改一个参数。改完代码、改配置、改硬件——三个一起改,出了问题你根本不知道是谁的锅。
2.3 常用基准测试工具
工具不在多,在于会用。我常用的就这几个:
2.3.1 Apache Bench (ab)
最简单的 HTTP 压测工具,适合快速验证。
# 并发 100,总共 10000 个请求
ab -n 10000 -c 100 http://localhost:8080/api/test
优点:轻量、自带。缺点:只能测 HTTP,不支持复杂场景。
2.3.2 wrk
比 ab 更现代,支持 Lua 脚本,可以模拟复杂请求。
# 4 个线程,100 个连接,持续 30 秒
wrk -t4 -c100 -d30s http://localhost:8080/api/test
我个人很喜欢 wrk,因为它能输出延迟分布,直接看到 TP99。
2.3.3 JMeter
功能最全,但配置也最复杂。适合做全链路压测。
- 支持多种协议(HTTP、JDBC、MQ)
- 有图形界面
- 可以分布式压测
嗯,这里要注意:JMeter 本身也是 Java 写的,压测机本身的内存和 GC 也会影响结果。我一般会用多台机器做分布式压测。
2.3.4 工具对比
| 工具 | 适用场景 | 学习成本 | 性能 |
|---|---|---|---|
| ab | 快速验证 | 低 | 一般 |
| wrk | 接口压测 | 中 | 高 |
| JMeter | 全链路压测 | 高 | 中 |
| Locust | Python 项目 | 中 | 中 |
2.4 基准测试流程:一个实战案例
光说不练假把式。我拿一个真实案例来演示:
场景:优化一个用户查询接口,目标是 QPS 从 500 提升到 2000。
步骤:
- 搭建隔离环境:一台 4C8G 的云服务器,关闭所有非必要服务。
- 预热:先跑 2 分钟请求,让 JIT 编译完成。
- 基线测试:用 wrk 测出当前性能。
- 优化:加缓存、改 SQL、调连接池。
- 对比测试:同样条件再测一次。
- 分析结果:看 QPS 和 TP99 的变化。
# 基线测试结果
wrk -t4 -c100 -d30s http://localhost:8080/user/query
Requests/sec: 512
Latency Distribution:
50% 45ms
99% 210ms
# 优化后测试结果
wrk -t4 -c100 -d30s http://localhost:8080/user/query
Requests/sec: 2150
Latency Distribution:
50% 12ms
99% 45ms
你看,QPS 从 512 涨到了 2150,TP99 从 210ms 降到了 45ms。这就是基准测试的价值——用数据说话。
2.5 小结
这一章我们聊了:
- 延迟、吞吐量、QPS、TP99 这些核心指标
- 基准测试的方法论——环境隔离、预热、控制变量
- 常用工具的选择和使用
- 一个完整的实战案例
记住一句话:没有度量,就没有优化。下一章,我们会深入代码层面,看看如何用 Profiling 工具找到真正的瓶颈。