第3章:性能基准测试
聊到性能调优,我第一个想跟你聊的,就是基准测试。
很多人一上来就搞优化,改配置、调参数、换框架……忙活半天,结果呢?
性能到底是变好了还是变差了?说不清楚。
这就是典型的「没有基准,就没有真相」。
基准测试,说白了就是给你的系统拍一张「体检照」。
你优化前拍一张,优化后再拍一张。两张一对比,效果一目了然。
什么是基准测试
基准测试(Benchmarking),是一种标准化的测试方法。
它的核心目的只有一个:在可控条件下,测量系统的性能指标。
我习惯把它分成两类:
- 微基准测试:针对一小段代码,比如一个算法、一个函数。测的是纳秒、微秒级别。
- 宏基准测试:针对整个系统,比如一个Web服务、一个数据库。测的是吞吐量、延迟。
你想想看,如果你连系统「正常时」的性能数据都没有,你怎么判断它「异常时」到底差了多少?
嗯,这就是基准测试存在的意义。
核心观点:没有基线,就没有优化。基准测试是性能调优的「第一块基石」。
基准测试的设计原则
我在项目中踩过不少坑。有一次,我测了一个接口的QPS,结果数据忽高忽低,完全没法用。
后来才发现,测试机器上跑着别的任务,CPU被抢了。
所以,设计基准测试时,有几个原则你必须记住:
- 可重复性:同样的条件,跑十次,结果应该差不多。如果波动大,说明环境没控制好。
- 隔离性:被测系统尽量独占资源。别一边跑测试,一边开浏览器看视频。
- 代表性:测试场景要贴近真实。别拿「Hello World」去压测一个电商系统。
- 可度量性:指标要明确。是测TPS?还是P99延迟?先想清楚。
- 预热期:很多系统有JIT编译、缓存填充。刚启动就测,数据不准。我一般会先跑几分钟「热身」。
我的小习惯:每次做基准测试,我都会记录下环境信息——CPU型号、内存大小、JVM参数、操作系统版本。这些细节,往往就是排查问题的关键线索。
常用基准测试工具
工具不在多,在于会用。我挑几个最常用的跟你聊聊。
JMH(Java Microbenchmark Harness)
如果你写Java,JMH是微基准测试的「标配」。
它由JVM专家开发,专门解决JVM预热、编译器优化、死代码消除等问题。
举个例子,你想比较两种字符串拼接方式的性能:
@Benchmark
public void testStringConcat() {
String s = "";
for (int i = 0; i < 1000; i++) {
s += i;
}
}
@Benchmark
public void testStringBuilder() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
}
跑完之后,JMH会告诉你:哪个方法更快,快了多少,置信区间是多少。
我曾经用JMH发现过一个诡异的性能问题——某个工具类的加锁方式不对,导致高并发下性能暴跌。没有JMH,这种问题很难定位。
wrk 和 ab
这两个是HTTP压测工具,用来测Web服务的吞吐量。
- ab(Apache Bench):老牌工具,简单直接。适合快速压测。
- wrk:新一代工具,支持Lua脚本,能模拟复杂场景。我个人更推荐wrk。
用wrk压测一个接口:
wrk -t12 -c400 -d30s http://localhost:8080/api/test
这条命令的意思是:用12个线程,保持400个并发连接,持续压30秒。
输出结果会告诉你:总请求数、每秒请求数(RPS)、延迟分布。
注意:压测时,别把目标机器压挂了。我曾经有一次压测太猛,直接把测试环境的数据库打崩了……嗯,从那以后,我每次压测都会先设一个「安全阈值」。
sysbench
sysbench是数据库和系统层面的基准测试工具。它支持CPU、内存、磁盘I/O、数据库(MySQL、PostgreSQL)等。
比如,测一下数据库的OLTP性能:
sysbench --db-driver=mysql --mysql-user=root --mysql-password=123456 \
--mysql-db=test --table-size=1000000 oltp_read_write run
它会生成一张大表,然后模拟读写操作,最后输出TPS、延迟、95%延迟等指标。
我习惯用sysbench做数据库的「基准快照」。每次数据库升级或参数调整后,跑一遍sysbench,对比数据,心里就有底了。
如何建立性能基线
建立性能基线,不是跑一次测试就完事了。它是一个持续的过程。
我的做法是这样的:
- 确定关键指标:比如TPS、P99延迟、CPU使用率、内存占用。别贪多,3-5个核心指标就够了。
- 固定测试环境:硬件、软件、网络、数据量,全部固定下来。每次测试都用同一套环境。
- 多次运行取均值:至少跑5次,去掉最高最低,取平均值。这样可以消除偶然波动。
- 记录上下文:把测试时间、代码版本、配置参数、环境信息都记录下来。方便以后回溯。
- 自动化执行:把基准测试集成到CI/CD流水线中。每次代码提交,自动跑一遍基线测试。如果性能下降超过阈值,立刻告警。
一句话总结:性能基线,就是你的「性能账本」。每次优化,都是在跟这个账本做对比。
本章知识体系
下面这张图,帮你梳理了本章的核心逻辑:
基准测试,是性能调优的起点。没有它,你所有的优化都是「盲人摸象」。
我建议你,从今天开始,给每个系统都建立一份性能基线。哪怕只是一个简单的压测脚本,也比「凭感觉」强一百倍。
最后一个小建议:基准测试的结果,一定要可视化。用折线图展示TPS趋势,用热力图展示延迟分布。数据一上图表,问题就藏不住了。