3. 性能基准测试:基准测试的目的、常用工具、如何设计测试场景

说到性能优化,我见过不少团队上来就改代码、调参数,忙活半天却不知道到底有没有效果。这就像蒙着眼跑步——你觉得自己很快,但实际呢?

基准测试,说白了就是给系统拍一张「体检照」。你得先知道它现在什么水平,才能判断优化有没有用。我个人习惯,任何优化动作之前,必须先跑一轮基准测试,把数据记录下来。这是底线。

核心观点: 没有基准,就没有优化。你无法管理你无法测量的东西。

3.1 基准测试的目的

基准测试不是为了好看的数字,而是为了回答几个关键问题:

  • 当前性能基线——系统现在到底能扛多少并发?响应时间是多少?
  • 优化效果验证——改完代码后,性能是变好了还是变差了?
  • 瓶颈定位——哪个环节最慢?是数据库、网络还是应用本身?
  • 容量规划——系统什么时候会撑不住?需要加多少机器?

我记得有一次,团队花了两周优化一个接口,自我感觉良好。结果一跑基准测试,发现响应时间只降了5%。为什么?因为瓶颈根本不在代码里,而在数据库的慢查询上。你看,没有基准测试,你连问题在哪都不知道。

3.2 常用工具介绍

工具不在多,在于用对。我常用的就三个,各有各的适用场景。

工具 适用场景 优点 缺点
wrk HTTP 接口压测,快速验证 轻量、单机可压出高并发、支持 Lua 脚本 不支持分布式、无图形界面
ab (Apache Bench) 简单 GET/POST 压测 系统自带、上手极快 功能单一、高并发下不准
JMeter 复杂业务场景、分布式压测 功能全面、支持多种协议、有 GUI 资源消耗大、脚本维护成本高

wrk 快速上手

我个人最喜欢 wrk,因为它够轻、够快。你想想看,一个命令行就能压出几万并发,多爽。

# 基本用法:压测 30 秒,12 个线程,400 个连接
wrk -t12 -c400 -d30s http://localhost:8080/api/test

# 输出示例
Running 30s test @ http://localhost:8080/api/test
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    45.67ms   12.34ms 198.00ms   75.00%
    Req/Sec     7,234.56   1,234.56  12,345.00   80.00%
  2592000 requests in 30.00s, 3.24GB read
Requests/sec:  86400.00
Transfer/sec:    110.59MB

这里要注意几个关键指标:Latency 看平均值和 P99,Req/Sec 看吞吐量。我曾经遇到过一个问题:wrk 压测时本地 CPU 先跑满了,结果压的不是服务,而是 wrk 自己。嗯,这时候你得调低线程数或者换台更强的机器。

ab 快速上手

ab 适合临时验证,比如你改了个配置,想快速看看效果。

# 1000 个请求,100 个并发
ab -n 1000 -c 100 http://localhost:8080/api/test

# 关键输出
Requests per second:    8500.00 [#/sec] (mean)
Time per request:       11.764 [ms] (mean)
Transfer rate:          112.34 [Kbytes/sec] received
注意: ab 在高并发下(比如超过 1000 并发)结果会失真。它本身是单线程模型,扛不住太高的压力。别拿它做严肃的容量测试。

JMeter 场景设计

JMeter 虽然重,但胜在灵活。我一般用它来做复杂的业务链路压测,比如用户登录 → 浏览商品 → 加入购物车 → 下单支付。这种场景 wrk 和 ab 搞不定。

设计 JMeter 脚本时,我习惯用 CSV Data Set Config 来驱动不同的参数,避免缓存命中导致结果虚高。你想想看,如果所有请求都用同一个用户 ID,那数据库的缓存一命中,响应时间自然好看,但真实场景根本不是这样。

3.3 如何设计测试场景

设计测试场景,比选工具重要得多。我见过太多人随便压一下,拿个数字就交差了。这其实是在骗自己。

我个人总结了一套「三步法」:

  1. 明确目标——你要测什么?是接口响应时间,还是系统最大吞吐量?目标不同,场景设计完全不同。
  2. 模拟真实流量——不要只压一个接口,要压完整的业务链路。用户不会只点一个按钮。
  3. 逐步加压——从低并发开始,慢慢往上加,直到系统崩溃。记录每个压力点的数据。
我的经验: 压测时一定要监控服务器资源(CPU、内存、IO、网络)。有时候响应时间变长了,不是因为代码慢,而是因为 CPU 被打满了。这时候你要优化的是资源,而不是代码。

3.4 基准测试流程框架

下面这张图是我自己总结的基准测试流程,每次做压测我都按这个来,基本不会漏掉关键环节。

基准测试流程框架 1. 明确测试目标 2. 设计测试场景 3. 选择压测工具 4. 执行压测并监控 5. 分析结果并记录 不达标则回退到步骤1

3.5 避坑指南

做了这么多年性能优化,我踩过的坑不少。分享几个最常见的:

  • 不要只压一次——至少跑三次,取平均值。网络抖动、GC 暂停都会影响单次结果。
  • 预热很重要——JVM 需要预热,缓存需要填充。先压个一两分钟,等数据稳定了再开始记录。
  • 监控客户端资源——我曾经用一台笔记本压线上服务,结果 wrk 自己先撑不住了。压测机的资源也要够。
  • 记录环境信息——压测时的 CPU 型号、内存大小、JVM 参数、网络带宽,全部记下来。不然过两周你都不知道这个数据是在什么环境下跑的。
特别提醒: 不要在线上环境直接压测!除非你做好了降级和熔断。我见过有人把线上数据库压挂的,那场面……嗯,你懂的。

3.6 小结

基准测试不是一次性工作,而是持续的过程。每次优化前后都要跑,数据要归档。这样你才能知道,你的优化到底值不值。

工具选 wrk 还是 JMeter,取决于场景。但不管用什么工具,场景设计才是灵魂。模拟真实流量、逐步加压、监控资源,这三件事做好了,基准测试就成功了一大半。