性能测试:JMeter 在接口高并发测试中的使用方法

一提到接口高并发测试, 默认想到的工具就是 JMeter

这没有问题。
JMeter 到今天依然是很实用的压测工具,尤其适合:

  • HTTP 接口压力测试
  • 快速构建可重复执行的脚本
  • 用非 GUI 模式接 Jenkins 或批量任务
  • 做中小到中大型的分布式压测

但如果把 JMeter 理解成“拖几个组件、配几个线程组、点一下开始执行”,那一旦进到高并发场景,结果就很容易失真。

因为高并发压测真正难的,从来不是“会不会发请求”,而是下面这些问题:

  • 并发模型到底接不接近真实业务
  • 压测机是不是先把自己打满了
  • 参数化和关联是不是足够真实
  • 连接有没有复用,端口会不会先耗尽
  • 分布式压测时 master / worker 自己会不会先成瓶颈
  • 压测结果到底是系统问题,还是脚本问题

所以这篇文章我想讲的不是 JMeter 的按钮和菜单,而是:

在接口高并发测试里,JMeter 应该怎么用,才能让结果更可信、更接近真实、更有排障价值。

一、JMeter 在高并发场景里最容易被误用的地方,不是组件,而是模型

很多压测结果不可信,并不是因为 JMeter 不行,而是因为压测模型本身就是错的。

在项目里见过最常见的几种误用,大概都集中在这里。

1. 把线程数当成真实并发

一上来最常见的问题是:

  • 1000 并发怎么配
  • 5000 线程够不够

但在 JMeter 里,线程数不是业务系统感知到的真实并发本身。
真实效果至少还会受到这些因素影响:

  • ramp-up
  • 响应时间
  • think time
  • keep-alive
  • 连接复用
  • 请求链路长短

如果这些条件没对齐,线程数再大,也不代表你的流量模型就真的合理。

2. 用单接口轰炸,试图得出系统结论

如果真实业务是:

  • 查询 60%
  • 提交 25%
  • 其他链路 15%

但你压测时只盯一个查询接口狠狠干,最后得出的更像“单点接口能力”,不是“系统业务承压能力”。

3. 参数全写死

这是高并发脚本最常见也最容易被低估的问题。
如果所有请求都打:

  • 同一个用户
  • 同一个商品
  • 同一组搜索词

那缓存命中、热点锁、会话冲突都会被扭曲,结果要么过于乐观,要么过于悲观。

二、在真实项目里,更先设计“流量组织方式”,再落 JMeter 脚本

如果要做高并发压测,通常不会先打开 JMeter,而会先回答:

这次到底是哪种负载类型?

1. 单接口极限摸底

目的:

  • 找单点上限
  • 看某个关键接口先卡在哪

这种场景下,JMeter 脚本可以更聚焦。

2. 混合业务压测

目的:

  • 接近真实线上业务结构
  • 观察多个链路之间如何相互影响

这种场景下,线程组和请求比例设计会复杂得多。

3. 峰值冲击

目的:

  • 看系统在短时间猛增流量时是否抖动
  • 验证限流、网关、线程池、连接池抗冲击能力

4. 长稳压

目的:

  • 看长时间运行是否退化
  • 是否有连接泄漏、缓存抖动、内存积压

如果这一步不先想清楚,JMeter 脚本写得越多,越容易跑偏。

三、怎么组织一套更适合高并发的 JMeter 脚本

高并发脚本最怕做成“大杂烩”。

一个更适合长期维护的结构,通常会拆成几层:

1
2
3
4
5
6
7
8
9
10
11
test-plan/
├── common-config
│ ├── user_defined_variables
│ ├── http_request_defaults
│ ├── http_header_manager
│ ├── http_cookie_manager
│ └── csv_data_set_config
├── scenario-login
├── scenario-query
├── scenario-submit
└── result-output

重点不在形式,而在职责清晰:

  • 公共配置放一起
  • 场景按业务拆
  • 参数化集中处理
  • 监听器尽量精简

否则脚本一大,后面改一个 header、一个 host、一个参数文件,都会牵一发动全身。

四、高并发下最重要的基础配置,不是多复杂,而是别失真

精力很容易被放到复杂组件上,但真实高并发里,最容易让结果失真的往往是一些看起来基础的配置。

1. HTTP Request Defaults

建议统一维护:

  • 协议
  • 域名
  • 端口
  • 编码
  • 超时

这一层如果分散在各采样器里,脚本一复杂就容易漂。

2. HTTP Header Manager

高并发时,Header 往往决定请求是不是接近真实客户端。
例如:

  • Content-Type
  • Authorization
  • User-Agent
  • 自定义业务头

如果 Header 和真实请求差太多,路由、鉴权、限流逻辑都可能变掉。

这里最关键的不是“要不要配”,而是你到底在模拟:

  • 每个线程独立会话
  • 还是某种共享会话模型

这两个模型压出来的结果完全不是一回事。

4. Keep-Alive

高并发下,连接复用非常关键。
如果 keep-alive 没配好,最容易出现的不是系统慢,而是压测机自己先爆:

  • 本地端口大量占满
  • TIME_WAIT 堆积
  • 建连成本被放大

然后问题还很容易被误判成服务端问题。

五、更看重 JMeter 脚本里的“压测机成本”,而不是只看被测系统

这是高并发压测里最容易忽略的一点。

常见的默认前提是:

  • 压测工具只是工具
  • 问题只会出在被测系统

但真实情况往往是,压测机本身经常先成为瓶颈。

尤其是并发一高,下面这些都可能先出问题:

  • 压测机 CPU
  • 压测机内存
  • 文件句柄
  • 本地端口范围
  • TIME_WAIT 回收
  • 网络带宽

所以高并发压测前,通常会先看:

  • ulimit
  • 本地端口范围
  • TCP 参数
  • 压测机 CPU / 内存 / 网卡

如果这些基础条件不对,JMeter 再怎么调都只是在放大工具侧噪音。

六、非 GUI 执行不是习惯问题,而是高并发的底线

GUI 模式当然适合调试,但一旦进入正式高并发执行,我基本只建议用:

1
jmeter -n -t test_plan.jmx -l result.jtl -e -o report/

原因不是“更专业”,而是:

  • GUI 自己就很耗资源
  • 高并发下监听器会明显拖慢执行
  • 正式执行更需要稳定和可重复

所以更常见的做法是:

  • GUI 调通脚本
  • 非 GUI 执行正式压测
  • 结果文件和报告按批次输出

七、分布式 JMeter 什么时候该用,什么时候别急着上

一看到“高并发”,最常见的第一版方案就是先上分布式。
但这个动作不适合太早做。

1. 单机能打够,就先单机

八、一套更接近项目落地的 JMeter 目录和执行方式

如果是要长期维护的接口压测,通常不会只保留一个 .jmx 文件。
更实用的做法是把脚本、数据、结果和执行命令分开。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
perf-jmeter/
├── jmx/
│ ├── login_and_query.jmx
│ └── submit_mix.jmx
├── data/
│ ├── users.csv
│ ├── goods.csv
│ └── tokens.csv
├── results/
│ └── 2023-04-22-stage3/
├── report/
└── README.md

更稳妥的做法是把执行说明也直接写进 README.md,避免换个人就不知道怎么复现:

1
2
3
4
5
6
7
8
9
jmeter -n \
-t jmx/login_and_query.jmx \
-l results/stage3.jtl \
-e -o report/stage3 \
-Jhost=10.10.10.20 \
-Jport=8080 \
-Jthreads=300 \
-Jrampup=180 \
-Jduration=1800

这种写法的好处是:

  • 环境变量和阶段参数能被显式记录
  • 每轮执行结果有独立目录
  • 后续复盘时能准确回放当时跑的是什么

九、在项目里更常用的升压节奏

高并发压测最怕一步到顶。
更常用的节奏是分阶段跑,每一阶段都要有明确观察点。

例如:

阶段 线程数 Ramp-Up 持续时间 目标
stage-1 100 60s 15m 验证脚本和环境正常
stage-2 200 120s 20m 观察吞吐是否线性增长
stage-3 300 180s 20m 找尾延迟和依赖抖动拐点
stage-4 400 240s 20m 判断是否进入风险区

每个阶段结束后,通常会立刻记三件事:

  • 当前 TPS / P95 / P99 / 错误率
  • 压测机 CPU、句柄、端口状态
  • 被测系统最先抬头的资源或依赖

十、正式执行前的 JMeter 自检

正式压测前,通常会先用一轮很轻的流量做自检。

最少会看这些点:

  • CSV Data Set Config 是否真的在轮转数据
  • 关键关联变量是否成功提取
  • 请求头和鉴权信息是否与真实客户端一致
  • 非 GUI 模式下结果文件是否正常落盘
  • 压测机是否出现端口、句柄、CPU 异常

如果是 Linux 压测机,通常还会顺手看几条命令:

1
2
3
4
ulimit -n
sysctl net.ipv4.ip_local_port_range
ss -s
top -H -p <jmeter_pid>

这几条命令不复杂,但能很快排除掉“不是系统扛不住,而是压测机先顶住”的情况。

因为单机的优点非常明显:

  • 简单
  • 排障快
  • 结果链路更清楚

2. 单机明显成为瓶颈,再考虑分布式

例如:

  • CPU 明显打满
  • 本地端口资源先耗尽
  • 网络带宽顶住

3. 上分布式以后,要单独关注 master 和 worker

只看 worker、不看 master,是很常见的误区。
这是很危险的,因为 master 还要承担:

  • 分发脚本
  • 汇总结果
  • 控制执行

如果 master 自己先顶住,整个压测结果同样会失真。

八、在项目里踩过的几个典型坑

坑 1:压测机先崩了,却以为系统扛不住

现象:

  • QPS 上不去
  • 错误开始增多
  • JMeter 本身明显发卡

最后查下来:

  • 压测机 CPU 满了
  • 本地端口耗尽
  • 监听器和断言过重

坑 2:模型很假,结果看起来却很漂亮

例如:

  • 请求对象太集中
  • 缓存命中过高
  • 数据冷热完全不接近真实

这种结果最危险,因为它会制造系统“已经很稳”的错觉。

坑 3:分布式压测里 worker 没问题,master 先成为瓶颈

这类问题很常见,但 第一反应不是去查 master,而是去怀疑服务端。

坑 4:只看 JMeter 报表,不看系统监控

JMeter 能告诉你的更多是:

  • 慢了
  • 错了
  • 吞吐掉了

但它不能替代:

  • JVM
  • 数据库连接
  • Redis 指标
  • 磁盘和网络

如果没有这些系统侧证据,很多结论都只能停留在“现象描述”。

九、更常用的排查顺序

如果一次高并发压测结果异常,通常按下面顺序看。

1. 先看压测模型是不是合理

确认:

  • 流量结构
  • 参数化
  • ramp-up
  • think time

2. 再看 JMeter 自己是不是先成瓶颈

确认:

  • 压测机 CPU / 内存
  • 句柄 / 端口
  • keep-alive
  • 监听器与断言负担

3. 再看被测系统的外部表现

确认:

  • 吞吐
  • P95 / P99
  • 错误率

4. 最后深入系统内部

确认:

  • 线程池
  • JVM / GC
  • 数据库
  • Redis
  • 磁盘
  • 网络

结语

JMeter 在接口高并发测试里依然很好用,但它真正难的地方从来不是“组件会不会拖”,而是能不能把流量模型、连接复用、参数分布、压测机资源和系统监控组织成一套可信的方案。

更准确地说,一次靠谱的 JMeter 高并发测试,至少要做到:

  • 模型接近真实业务
  • 基础配置不失真
  • 压测机不是隐形瓶颈
  • 正式执行走非 GUI
  • 结果解释要结合系统证据,而不是只看工具报表

如果这些基础没打好,JMeter 很容易变成一个“能打出数字但解释不了系统”的工具;
如果这些基础做扎实,它仍然是高并发接口测试里非常实用的一把老工具。