JMeter 性能测试实战:从脚本设计到非 GUI 压测与场景配

JMeter

安装及配置:https://bbs.huaweicloud.com/blogs/428927

语言设置:

性能测试

测试类型
  • 负载测试:确定系统在预期工作负荷下的表现,"你预期每天要背 10kg 的书包,负载测试就是看你背着 10kg 走 1 小时累不累"
  • 压力测试:不断加压,直到系统崩溃,以此找出系统的瓶颈和极限承载能力。"往你背上一直加砖头,直到你趴下为止,看你最后能扛起多少公斤"
  • 稳定性测试:在给定的负载下运行很长时间(如 24-72 小时),观察是否存在内存泄漏或资源耗尽。"让你背着 5kg 的包走上三天三夜,看你半路会不会因为体力透支倒下。"
  • 阶梯压力测试:通过由轻到重逐步增加并发,精准定位性能拐点
  • 性能测试的终极目标是找到瓶颈 (Bottleneck) 。当压力增加到一定程度时:
    1. 响应时间 (RT) 会突然飙升。
    2. 吞吐量 (TPS) 达到顶峰后不再增长,甚至开始下滑。
    3. 资源利用率(如 CPU)可能达到 90% 以上。
基本概念
指标名称 缩写 定义与理解
响应时间 RT 从用户发起请求到服务器返回结果的总时间。通常看 90% 响应时间(即 90% 的请求都在此时间内完成)比平均值更有参考价值。
并发用户数 Concurrency 同一时刻内,正在与系统进行交互的用户数量。注意:这不同于"在线用户数"。
每秒事务数 TPS 系统每秒能够处理的业务事务数量。这是衡量系统处理能力的核心指标。
每秒查询数 QPS 服务器每秒能够响应的查询次数(通常指数据库或接口的读取能力)。
吞吐量 Throughput 单位时间内系统处理的数据量(如 MB/s)或请求数。反映了系统的带宽限制和承载能力。
资源利用率 Utilization 测试期间服务器 CPU、内存、磁盘 I/O、网络带宽的使用百分比。

基本使用

  • 元件理解

  • 基本使用(目标:模拟 10 个用户,向一个假的 JSON API 发送 POST 请求,并验证返回结果)

    1. 分别按顺序添加(类比postman):测试计划、线程组()、HTTP请求(取样器)、http信息头(配置元件)、断言、监听器(聚合报告)

    2. 创建测试计划

    3. 添加线程组:10线程、10s启动、循环一次

    4. 添加 HTTP 请求(取样器):https、server_IP:jsonplaceholder.typicode.com、443、post、、posts(路径)、消息:{"title":"JMeter Test","body":"This is a test post","userId":1}

    5. 配置元件(config element):Content-Type:application/json

    6. 添加断言-响应断言:Response Code-Equals-201

    7. 添加查看结果树(view results tree)

    8. 添加监听器-聚合报告(Aggregate Report)

进阶一

参数化测试
  • 准备一个csv文件(90组数据)

    csv 复制代码
    postId
    1
    2
    3
  • 配置JMeter脚本

    • 创建计划

    • 添加线程组Thread Group:与csv中数量一致,N个账号选择N个线程,启动时间设置为性能要求时间,循环次数1次

    • 添加配置元件-csv数据文件设置CSV Data Set Config

    • 添加取样器-Http请求HTTP Requesthttps、jsonplaceholder.typicode.com、get、/post/${postId}

    • 添加断言中的json断言:

    • 添加查看结果树View Results Tree(请求的格式中 postId 被替换为csv文件的字段内容)

    • 添加聚合报告Aggregate Report,实际获取的报告如下:

      参数 值 (HTTP Request) 值 (TOTAL) 说明
      #Samples 90 90 总共发送了90个请求
      Average 1687 ms 1687 ms 平均响应时间1.68秒
      Median 1200 ms 1200 ms 中位数响应时间1.2秒
      90% Line 3128 ms 3128 ms 90%的请求在3.12秒内完成
      95% Line 3235 ms 3235 ms 95%的请求在3.23秒内完成
      99% Line 6508 ms 6508 ms 99%的请求在6.5秒内完成
      Min 832 ms 832 ms 最快响应832毫秒
      Max 7081 ms 7081 ms 最慢响应7.08秒
      Error % 0.000% 0.000% 错误率为0,所有请求成功
      Throughput 9.09/min 9.09/min 每分钟处理9.09个请求
      Received KB/sec 13.19 13.19 每秒接收13.19KB数据
      Sent KB/sec 1.54 1.54 每秒发送1.54KB数据
    • 注:

      • 请求的IP地址可以使用HTTP Request Defaults集中管理,后续只需要输入路径
      • 登录的token或者cookie 可以使用http cookie manager
      • 对于使用重定向项的这个可以使用HTTP URL Re-writing Modifier
关联测试
  • 添加json提取器,从请求中获取值然后写入变量,然后在新的请求中使用变量值(类似于postman的token写入然后再请求中携带)

  • JSR223 后置处理程序JSR223 PostProcessor

    groovy 复制代码
    props.put("global_token", vars.get("login_token")) // 获取线程变量设置为全局变量

进阶二

逻辑控制器

大型项目的模块化设计:

复制代码
测试计划
├── 用户定义的变量
├── CSV数据文件设置
├── 测试片段:登录模块
├── 测试片段:下单模块
├── 测试片段:支付模块
│
├── 线程组:混合场景测试
│   ├── 模块控制器 → 登录模块
│   ├── 模块控制器 → 下单模块
│   └── 模块控制器 → 支付模块
│
└── 线程组:独立场景测试
    ├── 模块控制器 → 下单模块
    └── 模块控制器 → 支付模块
测试片段
  • 作用:代码复用模块化管理
  • 使用:实际可以理解为函数调用,所以也包含:返回值,参数等类似操作;实际调用时在对应的线程组添加模块控制器(Module Controller)或者include Controller 选择文件为对应测试片段(单独保存的测试片段)
  • 返回值:在片段中添加如json提取器等方式获取返回值,将值写入变量,后续请求直接调对应变量即可${value}
  • 参数:在使用片段时直接在片段中使用变量
事务控制器
  • 用于做场景区分,在实际中可能会有多个场景,每个场景会有多个请求
循环控制器
  • 定义:重复运行部分请求

  • 注:

    • 循环控制器仅控制在其子请求

    • 与线程组的循环次数和线程数的区别:线程数表示用户数,即并发量;循环次数表示运行时间

      循环控制器表示执行对应请求(动作)的次数;比如:10个用户执行"登录-选购10件商品下单-结账"这个流程5次,所以挑选商品的请求次数为:10*5*10,循环次数为永远,时间为十分钟,那么就是:10*10*10分钟一直循环这个流程(响应越快,执行次数越多)

轮询机制
  • 适用场景:大部分异步任务场景 。需要根据响应结果决定是否继续轮询,并可设置超时退出。例如,你提交了一个报表生成任务,服务器返回一个任务ID,你需要不断地查询/task/status接口,直到返回"status": "success"才停止

  • 实际使用:

定时器

模拟真是用户在的思考时间

定时器类型 等待时间 适用场景 在你的测试中何时用
固定定时器 固定不变 有规律的轮询、固定的思考时间 轮询间隔3秒
高斯随机定时器 呈正态分布 更真实的用户行为模拟 模拟用户思考时间(有的快有的慢)
均匀随机定时器 在范围内随机 简单的随机间隔 模拟不规律的轮询
常数吞吐量定时器 动态调整 控制每秒请求数(TPS) 限制最大请求频率
同步定时器 等待所有线程到达 瞬间高并发(秒杀) 测试系统抗冲击能力
业务类型 建议思考时间 说明
轮询查询 1-5秒 太频繁会浪费资源,太慢影响用户体验
页面浏览 5-30秒 用户阅读内容的时间
表单填写 10-60秒 输入信息、思考答案的时间
登录操作 2-5秒 输入账号密码的常规时间
API调用 0-1秒 系统间调用通常无思考时间

进阶三

插件安装:https://jmeter-plugins.org/install/Install/

梯度压力测试:安装custom thread groups,线程组处添加jp@gc - Stepping Thread Group

Groovy 脚本常用场景

获取变量和设置变量

设置全局属性(跨线程通信)

获取响应内容

解析JSON

自定义断言

动态生成随机数据

响应时间图

  • 坐标轴含义:

    坐标轴 含义 说明
    X轴(横轴) 时间轴 显示测试运行的时间推移(单位:秒/分钟)
    Y轴(纵轴) 响应时间 显示请求的响应时间(单位:毫秒/秒)
    图例 请求类型 不同颜色的线条代表不同的HTTP请求
  • 响应图解读

    • 理想情况(系统性能稳定,负载处理能力良好):线条水平、波动小

      复制代码
      响应时间(ms)
      500 |----------------------------------------
          |    ~~~~    ~~~~    ~~~~    ~~~~    ~~~~
      0   +----------------------------------------
          时间 →
    • 持续上升(可能存在内存泄漏,导致系统越跑越慢、PS:可排除内存、数据库连接池):随着时间推移,响应时间不断增长

      复制代码
      响应时间(ms)
      2000 |                       /
          |                     /
      1000 |                   /
          |                 /
      500  |               /
          |    ~~~~      /
      0   +----------------------------------------
          时间 →
    • 阶梯上升(系统处理能力有限,并发增加导致请求排队;PS: 查看线程组设置,是否在不断增加并发):响应时间随着用户数增加呈阶梯状上升

      复制代码
      响应时间(ms)
      2000 |                     ____
          |                 ____/
      1500 |             ____/
          |         ____/
      1000 |     ____/
          |  __/
      500  |/
      0   +----------------------------------------
          时间 →
    • 剧烈抖动(系统极不稳定,可能有GC暂停、网络抖动、资源竞争;PS: 检查GC日志、网络延迟、数据库锁等待):响应时间忽高忽低,剧烈波动

      复制代码
      响应时间(ms)
      3000 |    /\    /\    /\    /\
          |   /  \  /  \  /  \  /  \
      2000 |  /    \/    \/    \/    \
          | /                       \
      1000 |/                         \
      0   +----------------------------------------
          时间 →
    • 突然飙升(系统达到瓶颈,开始出现性能拐点;PS:找到拐点对应的并发数,这就是系统的最大承载能力):运行一段时间后,响应时间突然急剧上升

      复制代码
      响应时间(ms)
      5000 |                         /
          |                       /
      3000 |                     /
          |                   /
      1000 |~~~~~~~~~~~~~~/
      0   +----------------------------------------
          时间 →

非 GUI 模式测试

GUI 模式适合编写脚本、调试请求、查看单次响应结果;正式性能测试建议使用非 GUI 模式执行,避免监听器和界面渲染占用大量客户端资源,导致压测机先成为瓶颈。

基本命令
bash 复制代码
jmeter -n -t test_plan.jmx -l result.jtl -e -o report
参数 说明
-n 非 GUI 模式运行
-t 指定 JMeter 测试计划文件
-l 指定结果文件,通常为 .jtl
-e 测试结束后生成 HTML 报告
-o HTML 报告输出目录,目录必须为空或不存在
带环境参数执行

可以通过 -J 传入环境变量,避免为不同环境维护多份 JMX 脚本。

bash 复制代码
jmeter -n -t api_test.jmx -l result.jtl -e -o report -Jhost=api.example.com -Jthreads=100 -Jduration=600

JMeter 中读取参数:

text 复制代码
${__P(host)}
${__P(threads,10)}
${__P(duration,60)}

说明:

  • ${__P(host)}:读取命令行传入的 host
  • ${__P(threads,10)}:读取 threads,如果未传入则默认使用 10
  • ${__P(duration,60)}:读取 duration,如果未传入则默认使用 60 秒。
推荐执行流程
  1. GUI 中完成脚本编写。
  2. 使用 View Results Tree 单线程调试请求、参数、断言、关联。
  3. 关闭或删除调试监听器。
  4. 小并发非 GUI 试跑,确认没有脚本问题。
  5. 正式压测使用非 GUI 模式执行。
  6. 根据 .jtl 和 HTML 报告分析结果。
  7. 结合服务端监控定位瓶颈。
注意事项
  • 正式压测不要开启 View Results Tree,它会保存大量请求和响应数据。
  • .jtl 文件名建议带上日期、场景和并发数,方便回溯,例如 login_100u_20260313.jtl
  • 每轮测试前确认报告目录为空,否则 -o 会执行失败。
  • 压测机自身也要监控 CPU、内存、网络和磁盘 I/O,避免客户端资源不足影响结论。

测试计划推荐结构

复杂压测脚本建议按"公共配置、数据准备、业务场景、数据清理"的方式组织。

text 复制代码
测试计划
├── 用户定义的变量(User Defined Variables)
├── HTTP请求默认值(HTTP Request Defaults)
├── HTTP信息头管理器(HTTP Header Manager)
├── HTTP Cookie管理器(HTTP Cookie Manager)
├── CSV数据文件设置(CSV Data Set Config)
├── setUp线程组
│   ├── 登录
│   ├── 获取Token
│   └── 准备测试数据
├── 线程组:核心业务场景
│   ├── 事务控制器:登录
│   │   └── HTTP请求:登录接口
│   ├── 事务控制器:查询
│   │   ├── HTTP请求:列表查询
│   │   └── HTTP请求:详情查询
│   ├── 事务控制器:下单
│   │   ├── HTTP请求:创建订单
│   │   ├── JSON提取器:提取orderId
│   │   └── HTTP请求:查询订单
│   └── 监听器:聚合报告(调试时使用)
└── tearDown线程组
    ├── 清理测试数据
    └── 退出登录
结构说明
  • User Defined Variables:存放公共变量,如协议、域名、端口、环境标识。
  • HTTP Request Defaults:统一管理协议、域名、端口,子请求只写路径。
  • HTTP Header Manager:统一管理 Content-TypeAuthorization 等请求头。
  • HTTP Cookie Manager:管理 Cookie 会话。
  • CSV Data Set Config:管理账号、参数化数据、业务数据。
  • setUp线程组:用于初始化操作,如登录、获取 Token、准备测试数据。
  • tearDown线程组:用于清理数据、恢复环境。
  • 事务控制器:按业务动作统计整体耗时,例如"下单"包含多个接口。
命名建议
  • 取样器使用业务名命名,例如 登录-获取Token订单-创建订单
  • 变量名使用小写加下划线,例如 ${access_token}${order_id}
  • 场景线程组命名包含目标,例如 负载测试-100并发-10分钟
  • CSV 文件命名包含用途,例如 users_100.csvorder_data.csv

测试前准备

准备项 说明
测试目标 例如验证 500 并发下登录接口 P95 小于 800ms,错误率小于 0.1%
测试环境 环境配置、服务器规格、数据库规格、网络链路、是否与生产一致
数据准备 测试账号、商品、订单、库存、幂等数据、清理策略
场景模型 登录、浏览、查询、下单、支付等业务占比
监控指标 应用、数据库、中间件、主机、网络、JVM、日志
退出条件 错误率过高、资源打满、服务不可用、影响共享环境

各场景推荐设置

不同压测场景的目标不同,线程数、启动时间、循环方式、定时器和断言策略也应不同。

场景配置总览
场景 目标 线程组/插件建议 Ramp-Up 持续时间 定时器建议 关注指标
普通负载测试 验证预期业务压力下是否稳定 Thread Group 平滑启动,30-300秒 10-30分钟 高斯随机/均匀随机定时器 P90/P95、TPS、错误率
瞬时负载测试 验证突发流量和秒杀场景 Thread Group + Synchronizing Timer 很短,0-10秒 1-5分钟 同步定时器 峰值响应时间、错误率、限流
稳定性测试 验证长时间运行是否退化 Thread Group 平滑启动,5-30分钟 8-72小时 真实思考时间 RT趋势、内存、GC、连接池
阶梯压力测试 找到性能拐点和最大承载能力 Stepping Thread Group / Ultimate Thread Group 分阶段增加 每阶段5-15分钟 按业务添加思考时间 TPS平台期、RT拐点、资源瓶颈
容量测试 确认系统最大可承载用户量 Stepping Thread Group 分阶段增加 到达瓶颈为止 按业务模型设置 最大TPS、最大并发、错误率
疲劳测试 验证资源泄漏和性能衰减 Thread Group 平滑启动 24小时以上 真实思考时间 内存增长、句柄、连接数、磁盘
普通负载测试

适用:验证系统在日常预期流量下是否满足性能要求。

推荐设置:

  • 线程数:按目标 TPS 和平均响应时间估算。
  • Ramp-Up:不要过短,建议让流量平滑进入目标负载。
  • 持续时间:至少 10-30 分钟,避免只看到短时结果。
  • 循环次数:建议勾选"永远",通过调度器控制持续时间。
  • 定时器:使用高斯随机定时器或均匀随机定时器模拟用户思考时间。
  • 断言:同时检查 HTTP 状态码和业务响应码。

示例:

text 复制代码
线程数:100
Ramp-Up:120秒
循环次数:永远
持续时间:1800秒
目标:P95 < 1s,错误率 < 0.1%
瞬时负载测试

适用:秒杀、抢券、批量提交、整点任务等瞬间高并发场景。

推荐设置:

  • 使用较短 Ramp-Up 或同步定时器。
  • Synchronizing Timer 设置集合点,让线程同时释放。
  • 同步定时器必须设置超时时间,避免线程一直等待。
  • 关注限流、排队、熔断、库存扣减、重复提交等问题。
  • 测试前准备足够数据,避免因为库存或账号不足导致误判。

示例:

text 复制代码
线程数:500
Ramp-Up:5秒
同步定时器用户数:500
同步定时器超时:10000ms
持续时间:60-300秒
稳定性测试

适用:验证服务长时间运行是否存在内存泄漏、连接泄漏、性能下降。

推荐设置:

  • 负载不要直接打到极限,建议使用预期峰值的 60%-80%。
  • 持续时间建议 8 小时以上,重要系统可跑 24-72 小时。
  • 保留真实思考时间,不要无间隔空转请求。
  • 每隔固定时间记录一次服务端资源指标。
  • 重点观察响应时间是否持续上升,而不是只看最终平均值。

示例:

text 复制代码
线程数:200
Ramp-Up:600秒
循环次数:永远
持续时间:86400秒
思考时间:2-10秒随机
关注:内存、GC、连接池、线程数、磁盘、日志量
阶梯压力测试

适用:定位系统从正常到瓶颈的拐点。

推荐设置:

  • 使用 jp@gc - Stepping Thread GroupUltimate Thread Group
  • 每个阶梯保持足够时间,至少能观察到 TPS 和 RT 是否稳定。
  • 每次增加并发后观察 P95、TPS、错误率和资源利用率。
  • 当 TPS 不再增长、RT 明显升高或错误率升高时,通常说明接近瓶颈。

示例:

text 复制代码
初始线程数:50
每阶段增加:50
每阶段持续:10分钟
最大线程数:500
停止条件:错误率 > 1% 或 P95 明显超过目标
容量测试

适用:确认系统最大能承载多少并发、最大 TPS 是多少。

推荐设置:

  • 从低并发开始,逐步增加压力。
  • 不建议一次性把线程数拉满,否则难以定位拐点。
  • 需要服务端完整监控配合,包括 CPU、内存、数据库、缓存、中间件。
  • 记录每个压力点的 TPS、P95、错误率和资源利用率。

结论输出建议:

text 复制代码
系统在 300 并发时 TPS 达到 850,P95 为 780ms,错误率 0.05%;
当并发提升到 400 时,TPS 不再增长,P95 升至 2.8s,数据库CPU接近 90%;
因此当前环境建议容量上限按 300 并发评估,瓶颈主要在数据库。
场景设置注意事项
  • 测试前先单线程跑通脚本,确认断言、参数化、关联都正确。
  • 正式压测时关闭调试监听器,只保留必要结果输出。
  • 压测数据要足够,账号、库存、订单、任务 ID 不要互相污染。
  • 如果接口有缓存,需区分冷缓存和热缓存场景。
  • 压测结论必须结合服务端监控,不能只看 JMeter 聚合报告。