2. 性能基准测试:基准测试方法论、常用压测工具(wrk/ab/locust)、测试环境搭建、结果解读
各位好,咱们今天聊聊性能基准测试。说实话,我见过太多团队一上来就对着线上系统猛怼,结果把数据库打挂了,还一脸懵。其实,基准测试就像给系统做体检——你得先知道它健康的时候什么样,才能判断它什么时候生病了。
2.1 基准测试方法论
基准测试不是随便跑个压测就完事了。我个人习惯把它分成三个步骤:定义指标 → 控制变量 → 重复验证。
第一步,定义指标。你想想看,没有指标怎么衡量好坏?常用的有:
- 吞吐量(Throughput):单位时间内能处理多少请求。比如 QPS(每秒查询数)、RPS(每秒请求数)。
- 延迟(Latency):单个请求从发出到收到响应的时间。重点关注 P50、P95、P99 分位值。
- 错误率(Error Rate):失败的请求占总请求的比例。一般要求低于 1%。
- 资源利用率:CPU、内存、磁盘 I/O、网络带宽的使用情况。
第二步,控制变量。这是最容易翻车的地方。我在项目中遇到过,有人压测时发现 QPS 忽高忽低,查了半天,原来是同一台机器上跑了个定时任务在抢 CPU。所以,压测前一定要确保:
- 压测机和目标机网络隔离,别互相干扰。
- 目标机上的其他服务尽量停掉。
- 压测参数(并发数、请求体大小)保持一致。
第三步,重复验证。一次压测结果不能说明问题。我一般会跑 3 次,取中位数或平均值。如果结果波动超过 10%,说明环境有问题,得排查。
核心原则:基准测试不是为了证明系统有多快,而是为了找到系统的瓶颈在哪里。
2.2 常用压测工具
工具这东西,没有最好的,只有最合适的。我根据场景选工具,下面聊聊三个常用的。
2.2.1 wrk
wrk 是我个人最常用的工具。它基于事件驱动,用 Lua 脚本可以定制请求。优点是轻量、性能高,单机就能压出很高的 QPS。缺点是不支持分布式,适合单机压测。
安装很简单:
# macOS
brew install wrk
# Linux
git clone https://github.com/wg/wrk.git
cd wrk && make
基本用法:
wrk -t12 -c400 -d30s http://localhost:8080/api
这条命令的意思是:用 12 个线程,保持 400 个并发连接,持续压 30 秒。
输出结果解读:
Running 30s test @ http://localhost:8080/api
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 45.67ms 12.34ms 123.45ms 75.00%
Req/Sec 8,234.56 1,234.56 12,345.67 80.00%
246,789 requests in 30.00s, 35.67MB read
Requests/sec: 8,226.30
Transfer/sec: 1.19MB
看什么?看 Latency 的平均值和标准差,标准差越小说明延迟越稳定。再看 Requests/sec,这就是吞吐量。
2.2.2 ab(Apache Bench)
ab 是 Apache 自带的压测工具,简单粗暴。优点是安装方便(一般系统自带),缺点是功能单一,不支持复杂的请求场景。
ab -n 10000 -c 100 http://localhost:8080/api
这条命令:总共发 10000 个请求,并发 100 个。
输出结果:
Concurrency Level: 100
Time taken for tests: 12.345 seconds
Complete requests: 10000
Failed requests: 0
Requests per second: 810.23 [#/sec] (mean)
Time per request: 123.456 [ms] (mean)
注意看 Failed requests,如果有失败,说明系统扛不住了。
小技巧:ab 的 -k 参数可以开启 HTTP Keep-Alive,能压出更高的吞吐量。但要注意,线上环境不一定开了 Keep-Alive,别被数据骗了。
2.2.3 Locust
Locust 是用 Python 写的,支持分布式压测。它的特点是:你可以用 Python 代码定义用户行为,模拟真实的业务场景。
安装:
pip install locust
写一个简单的压测脚本 locustfile.py:
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 5) # 用户等待时间 1-5 秒
@task
def index(self):
self.client.get("/api")
启动:
locust -f locustfile.py --host=http://localhost:8080
然后打开浏览器访问 http://localhost:8089,就能看到 Web 界面了。你可以实时调整并发数,观察 QPS 和延迟的变化。
Locust 的优点是灵活,缺点是需要写代码,而且单机性能不如 wrk。
2.3 测试环境搭建
环境搭建这块,我踩过不少坑。说白了,压测环境越接近线上,结果越可信。
硬件层面:
- 压测机和目标机最好用同一网段的物理机或云服务器,别用笔记本压服务器,网络延迟差异太大。
- 目标机的 CPU、内存配置要和线上一致。如果线上是 8 核 16G,压测机也最好一样。
软件层面:
- 关闭不必要的系统服务,比如防火墙、SELinux、自动更新。
- 调整系统参数。我记得有一次压测,发现 QPS 上不去,最后发现是
ulimit -n太小了,文件描述符不够用。
# 临时调整
ulimit -n 65535
# 永久调整(/etc/security/limits.conf)
* soft nofile 65535
* hard nofile 65535
网络层面:
- 确保压测机和目标机之间没有网络瓶颈。可以用
iperf测一下带宽。 - 如果压测机在公网,目标机在内网,那压测结果基本就是网络延迟,没有参考价值。
警告:千万不要在线上环境直接压测!我曾经见过有人把线上数据库压挂了,导致业务中断 2 小时。压测一定要在隔离的测试环境进行。
2.4 结果解读
拿到压测结果后,怎么分析?我一般按这个顺序来:
- 看错误率:如果有错误,先排查错误原因。可能是并发太高导致连接超时,也可能是后端服务挂了。
- 看吞吐量:QPS 或 RPS 是否达到预期?如果没达到,说明系统有瓶颈。
- 看延迟分布:P50 低不代表 P99 低。如果 P99 很高,说明系统在某些情况下响应很慢,可能是 GC 停顿、锁竞争或者慢查询。
- 看资源利用率:CPU 是否跑满?内存是否够用?磁盘 I/O 是否成为瓶颈?
举个例子,有一次我压测一个 Java 服务,发现 QPS 只有 2000,但 CPU 只用了 30%。这说明瓶颈不在 CPU,可能在数据库或者网络。后来一查,果然是数据库连接池太小了。
下面这张图是我总结的基准测试知识体系,你可以对照着看:
最后,我想说一句:基准测试不是一次性工作。每次代码变更、配置调整、硬件升级后,都应该重新跑一遍。只有这样,你才能对系统的性能心中有数。
我的习惯:每次压测后,我都会把结果记录到一个表格里,包括测试时间、环境配置、压测参数、QPS、P99 延迟等。这样下次对比时,一眼就能看出变化。
好了,关于基准测试的方法论、工具、环境搭建和结果解读,就聊到这里。记住,实践出真知,多压几次,你自然就找到感觉了。