JMeter 性能测试教程

JMeter 性能测试教程

从零开始学习 Apache JMeter:安装、编写测试脚本、参数化、断言、关联、压力测试与报告生成。

本仓库附带一个可直接运行的示例测试计划:`examples/demo-api.jmx`

1. 什么是 JMeter

Apache JMeter 是 Apache 基金会出品的一款开源的、基于 Java 的压力测试工具。它原本用于 Web 应用性能测试,后来扩展为支持多种协议:

协议

用途

协议

用途

HTTP / HTTPS

Web 接口、网页性能测试

FTP

文件上传下载

JDBC

数据库性能测试

JMS

消息队列

TCP / UDP

自定义协议

WebSocket / gRPC(插件)

现代应用

JMeter 能做什么:

  • 模拟成百上千的并发用户
  • 对接口做负载 / 压力 / 稳定性测试
  • 用断言校验响应是否正确
  • 参数化与关联,模拟真实业务场景
  • 生成聚合报告与 HTML 图表报告

JMeter 不是浏览器的替代品:它不执行 JS / CSS 渲染(除非使用 Selenium / WebDriver 插件)。做纯接口性能测试它是最佳选择之一。

2. 安装与启动

2.1 环境要求

  • JDK 8+(JMeter 5.x 建议 JDK 8~11,JMeter 5.5 之后需 JDK 8+,部分新版本需 11+)
  • 不需要安装 Tomcat 等容器,JMeter 是独立程序

2.2 下载

官方下载页:<https://jmeter.apache.org/download_jmeter.cgi>

  • 选择 apache-jmeter-x.x.zip(Windows)或 .tgz(Linux/macOS)
  • 解压即可,无需安装

2.3 启动

# 进入解压后的 bin 目录

cd apache-jmeter-5.6.3/bin

 

# Windows

jmeter.bat

 

# Linux / macOS(需要执行权限)

./jmeter

提示:jmeter.bat 打开的是 GUI(图形界面)。性能测试时务必使用命令行模式(见 第 13 节),GUI 只用于编写和调试脚本。

2.4 界面速览

图 1 JMeter 主界面:菜单栏、工具栏、左侧测试计划树与右侧配置面板(整棵树已展开)

启动后默认打开测试计划编辑器。常用区域:

  • 左侧树:测试计划结构(Test Plan 根节点、线程组、采样器等)
  • 右侧面板:选中节点的配置区域
  • 菜单栏:File / Edit / Run / Options 等

3. 核心概念

JMeter 的一切都是建立在下面的树形结构上:

Test Plan(测试计划)

└── Thread Group(线程组)

    ├── Config Element(配置元件):如 HTTP 请求默认值、CSV 数据

    ├── Sampler(采样器):如 HTTP 请求、JDBC 请求

    ├── Logic Controller(逻辑控制器):循环、条件、随机等

    ├── Timer(定时器):控制请求间隔

    ├── Assertion(断言):校验结果

    └── Listener(监听器):查看/保存结果

概念

说明

概念

说明

Test Plan

整个测试的根节点,可配置全局变量、线程组执行策略

Thread Group

一组虚拟用户。线程数 = 并发用户数,Ramp-Up 表示多久启动完所有线程

Sampler

真正发起请求的组件,如 HTTP Request

Config Element

提供默认值 / 数据源,如 HTTP Request Defaults、CSV Data Set Config

Logic Controller

控制采样器的执行顺序和次数,如 Loop Controller、If Controller

Timer

控制请求之间的间隔,模拟用户思考时间

Assertion

校验响应是否符合预期,失败则标记该请求为错误

Listener

收集并展示结果,如 View Results Tree、Aggregate Report

执行顺序:配置元件 → 前置处理器 → 定时器 → 采样器 → 断言 → 后置处理器 → 监听器(同一作用域内按此顺序执行)。

4. 第一个测试计划

下面创建一个访问 https://httpbin.org/get 的最小测试计划。

4.1 新建并保存

  1. 打开 JMeter,测试计划会自动创建,命名为 Test Plan
  2. 点击 File → Save As,保存为 first-test.jmx

4.2 添加线程组

图 2 线程组面板:设置线程数、Ramp-Up 时间与循环次数

  1. 右键 Test Plan → Add → Threads (Users) → Thread Group
  2. 配置:
  • 线程数(Number of Threads):10
  • Ramp-Up 时间(秒):5
  • 循环次数(Loop Count):1

4.3 添加 HTTP 请求

  1. 右键线程组 → Add → Sampler → HTTP Request
  2. 配置:
  • 协议:https
  • 服务器名称:httpbin.org
  • 方法:GET
  • 路径:/get

4.4 添加监听器

  1. 右键线程组 → Add → Listener → View Results Tree
  2. 右键线程组 → Add → Listener → Summary Report

4.5 运行

点击工具栏绿色 启动 按钮。运行后:

  • View Results Tree 中可查看每个请求的响应体、响应头
  • Summary Report 显示平均响应时间、吞吐量、错误率

一个合格测试计划的最低配置:线程组 + 采样器 + 断言 + 监听器。请记住:只有加断言,测试结果才有意义

5. HTTP 请求详解

5.1 核心字段

图 3 HTTP 请求面板:协议、服务器、方法与路径等核心字段

字段

说明

示例

字段

说明

示例

协议

http / https

https

服务器名称或 IP

主机名,可包含端口

httpbin.org 或 10.0.0.1:8080

方法

GET / POST / PUT / DELETE 等

POST

路径

接口路径

/api/login

Content encoding

编码,建议 UTF-8

UTF-8

参数

GET 查询参数 或 表单参数

name=john

Body Data

请求体(POST 常用)

JSON 字符串

5.2 GET 请求

路径:/get

参数(Query String):

  name = john

  age  = 18

等价于请求 https://httpbin.org/get?name=john&age=18

5.3 POST JSON 请求

方法:POST

路径:/post

Content encodingUTF-8

Body Data

{"username": "admin", "password": "123456"}

5.4 设置请求头(HTTP Header Manager)

图 4 HTTP Header Manager:为请求添加请求头

右键采样器 → Add → Config Element → HTTP Header Manager,添加:

Content-Type: application/json

Authorization: Bearer <token>

5.5 复用公共配置(HTTP Request Defaults)

如果多个请求都访问同一个服务器,右键线程组 → Add → Config Element → HTTP Request Defaults,统一配置协议和服务器名。子级采样器无需重复填写。

把不变的配置放在 HTTP Request Defaults,变的部分写在采样器里,脚本更易维护。

6. 断言(Assertions)

断言用于校验响应是否符合预期,是判断请求“成功/失败”的依据。

6.1 响应断言(Response Assertion)

图 5 响应断言面板:校验响应是否包含指定文本

右键采样器 → Add → Assertions → Response Assertion

配置示例:

要测试的模式:     响应文本(Response Text

匹配规则:         包含(Contains

要测试的模式:     "success": true

常用匹配规则:

规则

说明

规则

说明

包含(Contains)

响应中是否包含指定文本(子串匹配)

匹配(Matches)

正则匹配整个响应

等于(Equals)

完全相等

字符串(Substring)

与 Contains 类似,无正则语法

6.2 断言失败时的表现

  • 请求在结果树中显示为红色
  • 汇总报告中的错误率(Error %)上升
  • 可通过 Response Assertion 的“自定义失败消息”查看失败原因

6.3 JSON 断言

右键采样器 → Add → Assertions → JSON Assertion

JSON Path$.success

Expected Valuetrue

要求返回的 JSON 中 success 字段为 true。

6.4 持续时间断言(Duration Assertion)

用于校验响应时间不超过阈值:

Duration1000   (毫秒,超过 1 秒视为失败)

7. 参数化

参数化让不同虚拟用户使用不同数据,更贴近真实场景。

7.1 用户自定义变量(User Defined Variables)

右键线程组 → Add → Config Element → User Defined Variables

host     = https://httpbin.org

username = test01

在采样器中使用 ${host}、${username} 引用。

7.2 CSV 数据驱动(CSV Data Set Config)

图 6 CSV Data Set Config:数据驱动参数化

步骤 1:准备 users.csv:

username,password

test01,123456

test02,abcdef

test03,xyz789

步骤 2:右键线程组 → Add → Config Element → CSV Data Set Config,配置:

字段

字段

文件名

users.csv(绝对路径或相对 bin 目录)

文件编码

UTF-8

变量名称

username,password

分隔符

,

是否忽略首行

True(跳过表头)

循环模式

可设置 Recycle 为 True(数据用完重新开始)

步骤 3:在 HTTP 请求参数 / Body 中使用:

Body Data{"username": "${username}", "password": "${password}"}

步骤 4线程数设为 CSV 数据行数,每个线程读取一行,实现多用户登录压测。

7.3 内置函数(Functions)

右键参数输入框 → Generate,或直接手写函数:

函数

作用

示例

函数

作用

示例

${__threadNum}

当前线程号

${__threadNum}

${__time(YYYY-MM-dd)}

当前时间

${__time(2024-01-01)}

${__Random(1,100)}

随机数

${__Random(1,100)}

${__UUID}

随机 UUID

${__UUID}

${__CSVRead(file,index)}

读取 CSV 指定列

${__CSVRead(users.csv,0)}

8. 关联

实际场景中,登录后返回的 token 往往要传给后续请求使用,这称为关联

8.1 正则表达式提取器(Regular Expression Extractor)

图 7 正则表达式提取器:提取 token 实现关联

场景:登录接口返回 {"token": "abc123"},订单接口需要在 Header 中使用它。

  1. 在登录采样器上右键 → Add → Post Processors → Regular Expression Extractor
  2. 配置:

Apply toMain sample

字段:响应文本

引用名称(Reference Name):token

正则表达式:\{"token": "(.+?)"\}

模板:$1$

匹配数字:1

默认值:NOT_FOUND

  1. 在订单请求的 Header 中引用:Authorization: Bearer ${token}

正则中 (.+?) 是非贪婪匹配,用于提取括号内的内容。模板 $1$ 表示取第一个分组。

8.2 JSON 提取器(JSON Extractor)

图 8 JSON Extractor:用 JSON Path 提取字段

需要 JSON Path 更直观:

引用名称:token

JSON Path$.token

步骤:右键登录采样器 → Add → Post Processors → JSON Extractor

9. 逻辑控制器

控制采样器的执行逻辑。

控制器

作用

控制器

作用

Loop Controller

循环执行子节点 N 次

If Controller

满足条件才执行

While Controller

满足条件时一直循环

Random Controller

随机执行其中一个子节点

Transaction Controller

把一组请求合并为一个事务统计

Interleave Controller

轮流执行子节点

ForEach Controller

遍历变量数组

示例:事务控制器

图 9 事务控制器:把一组请求合并为一个事务统计

把“下单流程”(登录 → 创建订单 → 查询订单)包进 Transaction Controller,报表中会把它当做一个整体事务统计耗时。

勾选 Generate parent sample 后,事务控制器本身也会生成一条汇总记录,便于统计完整业务链路的耗时。

10. 定时器

定时器控制请求发送的节奏,避免所有线程在瞬间发出请求。

定时器

说明

定时器

说明

Constant Timer

固定等待 N 毫秒

Gaussian Random Timer

服从高斯分布的随机延迟,更贴近真实用户

Uniform Random Timer

均匀分布的随机延迟

Constant Throughput Timer

控制吞吐量(每分钟请求数)

Synchronizing Timer

集合点,让所有线程同时发起请求

示例:模拟思考时间

线程组下添加 Gaussian Random Timer:

延迟范围:500  ms   (基础 0.5 秒)

标准差:  100  ms

示例:集合点(并发瞬间压测)

图 10 集合点定时器:等待 N 个线程同时发起请求

右键线程组 → Add → Timer → Synchronizing Timer

Number of Simulated Users to Group100

Timeout in milliseconds5000

即:等 100 个线程都到达后,一起发出请求,用于测试服务端瞬间峰值并发能力。

11. 压力测试与并发

11.1 线程组参数含义

参数

说明

参数

说明

Number of Threads

虚拟用户总数(并发数)

Ramp-Up Period

启动所有线程花费的时间(秒)。0 表示立即全部启动

Loop Count

每个线程循环执行的次数。勾选 Forever 表示一直跑,直到手动停止

Same user on each iteration

勾选后,每个迭代使用同一用户数据(配合 CSV 保持登录态时有用)

11.2 Ramp-Up 的计算建议

Ramp-Up ≈ 并发数 / 每秒目标启动数

  • 想要 1 秒启动 5 个线程,100 并发 → Ramp-Up = 20
  • 压测通常建议 Ramp-Up 给 5~10 秒,避免启动风暴把网络/代理打满

11.3 常用测试类型

类型

线程数

循环

说明

类型

线程数

循环

说明

冒烟测试

1~10

1~3

验证脚本正确、环境连通

负载测试

50~500

N

观察系统在预期负载下的表现

压力测试

逐步增加

Forever

找到系统拐点 / 最大承载

稳定性测试

适中

Forever

长时间运行(如 8 小时)看资源是否泄漏

11.4 压测通用流程

  1. 先小并发冒烟,确认脚本无误
  2. 用少量线程 + 循环验证断言正确性
  3. 逐步增加线程数,观察吞吐量(TPS)与响应时间曲线
  4. 找到拐点:TPS 不再增长、错误率上升的时间点即系统瓶颈

重要:压测请使用命令行模式(第 13 节),GUI 本身会消耗资源且影响结果,切勿用 GUI 做高压测试。

12. 查看与生成报告

12.1 常用监听器

图 11 View Results Tree:查看单个请求的请求/响应细节

图 12 Summary Report:平均/中位数/90% 分位/吞吐量/错误率

监听器

用途

监听器

用途

View Results Tree

查看单个请求的请求/响应细节,调试用

Summary Report

汇总:平均、中位数、90% 分位、吞吐量、错误率

Aggregate Report

类似 Summary,含 Min/Max/StdDev

Assertion Results

只看断言失败信息

Graph Results

曲线图

Response Time Over Time

响应时间随时间变化(需插件)

12.2 生成 HTML 报告

先在命令行跑一次并保存结果,然后生成报告:

# 运行并保存结果到 result.jtl

jmeter -n -t test.jmx -l result.jtl -e -o report-dir

参数说明:

参数

含义

参数

含义

-n

非 GUI 模式

-t

指定测试计划 .jmx 文件

-l

结果日志文件 .jtl

-e

测试结束后生成 HTML 报告

-o

HTML 报告输出目录(必须为空或不存在)

生成后打开 report-dir/index.html 即可看到图表化报告(吞吐量、响应时间分位数、活跃线程数等)。

13. 命令行(非 GUI)运行

压测和 CI 集成时使用命令行模式:

# 基础运行

jmeter -n -t demo-api.jmx -l result.jtl

 

# 运行 + 生成 HTML 报告

jmeter -n -t demo-api.jmx -l result.jtl -e -o html-report

 

# 通过参数覆盖脚本中的自定义变量(如服务器地址)

jmeter -n -t demo-api.jmx -Jhost=httpbin.org -Jthreads=50 -l result.jtl

脚本中引用自定义属性:${__P(host,httpbin.org)}、${__P(threads,10)}。

远程分布式压测:jmeter -n -R <slave_ip> 可调用远程机执行,具体配置见官方文档。

14. 常用函数与变量

14.1 变量引用方式

写法

说明

写法

说明

${var}

引用变量/参数

${__P(name,default)}

命令行参数,可给默认值

${__property(name)}

引用 properties 文件属性

${__V(expr)}

动态求值(嵌套变量时用)

14.2 高频函数速查

函数

返回值

示例

函数

返回值

示例

${__Random(1,9999)}

随机整数

${__Random(1,9999)}

${__time(/1000)}

当前时间戳(秒)

${__time(/1000)}

${__time(YYYY-MM-dd HH:mm:ss)}

格式化时间

${__time(2026-08-14 12:00:00)}

${__UUID}

UUID 字符串

${__UUID}

${__threadNum}

当前线程号

${__threadNum}

${__counter(FALSE,id)}

计数器

${__counter(FALSE,id)}

${__evalVar(var)}

变量求值

${__evalVar(host)}

${__intSum(a,b)}

整数求和

${__intSum(100,${n})}

14.3 JMeter 内置属性

  • ${JMeterThread.last_sample_ok}:上一个采样器是否成功(true/false)
  • ${prev}:前一个采样器的 SampleResult 对象
  • ${vars}:变量容器(可在 JSR223 中使用)

15. 最佳实践

  1. 不要用 GUI 压测:GUI 用于编写和调试,正式压测一律命令行(-n)。
  2. 必须加断言:没有断言,错误率永远是 0,结果无意义。
  3. 使用 HTTP Request Defaults:统一协议/服务器,减少重复配置、便于迁移环境。
  4. 参数化数据:用 CSV 模拟多用户,避免全部线程用同一账号导致服务端缓存干扰结果。
  5. 合理设置 Ramp-Up:不要 0 秒瞬间启动所有线程,除非专门测集合点。
  6. 分离测试环境:压测会影响被测系统性能,不要在生产直接压(除非有明确授权)。
  7. 先小规模验证:10 并发跑通后再放大并发。
  8. 监控服务端资源:结合 CPU / 内存 / 数据库连接等指标定位瓶颈,别只看 JMeter 数字。
  9. 保持脚本简单:优先用内置组件,JSR223 脚本(Groovy)慎用且要注意性能。
  10. 结果可复现:固定线程数、循环、定时器,避免用 GUI 手动点来点去。
  11. 不要超时中断:设置合理的连接/响应超时(如 10s),否则 JMeter 会长时间挂起。

16. 常见问题

Q1:启动时提示找不到 Java?

安装 JDK 8+ 并配置 JAVA_HOME 环境变量,重启终端后再启动。

Q2:提示 `OutOfMemoryError`?

修改 bin/jmeter.bat 中的堆内存参数:

set HEAP=-Xms512m -Xmx2g

Q3:为什么响应时间看起来很大?

  • 是否包含了思考时间(定时器)
  • 是否在 GUI 里运行(GUI 影响性能)
  • 采样器是否设置了超时,被网络阻塞挂起

Q4:CSV 中文乱码?

文件保存为 UTF-8(可用 notepad++/VS Code 转换),并在 CSV Data Set Config 中设置文件编码为 UTF-8。

Q5:如何保持登录态?

图 13 HTTP Cookie Manager:自动保存并携带 Cookie 保持登录态

  • 用 HTTP Cookie Manager(右键线程组 → Add → Config Element → HTTP Cookie Manager)
  • 跨线程组共享登录态时,可把 token 写入文件或用 setProperty / ${__property} 传递

Q6:如何只看失败请求?

View Results Tree 顶部筛选框输入 Error,或直接看 Assertion Results 监听器。

Q7:JMeter 与 Selenium 的区别?

JMeter 走 HTTP 协议层,不渲染页面;Selenium 是真浏览器。性能测试用 JMeter,功能/UI 测试用 Selenium。

附:示例测试计划

仓库中附带 `examples/demo-api.jmx`:

  • 线程组:10 个线程,5 秒 Ramp-Up,循环 3 次
  • HTTP 请求:GET https://httpbin.org/get?name=${__threadNum}
  • 断言:响应包含 "args",且响应时间小于 5000ms
  • 监听器:View Results Tree + Summary Report

运行方式:

jmeter -n -t examples/demo-api.jmx -l result.jtl -e -o report

注意:httpbin.org 为公网免费测试服务,网络波动可能影响结果,仅用于学习。

参考资源

  • 官方文档:<https://jmeter.apache.org/usermanual/>
  • 下载地址:<https://jmeter.apache.org/download_jmeter.cgi>
  • 插件仓库(官方之外,用于增强图表等):<https://jmeter-plugins.org/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值