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 新建并保存
- 打开 JMeter,测试计划会自动创建,命名为 Test Plan
- 点击 File → Save As,保存为 first-test.jmx
4.2 添加线程组

图 2 线程组面板:设置线程数、Ramp-Up 时间与循环次数
- 右键 Test Plan → Add → Threads (Users) → Thread Group
- 配置:
- 线程数(Number of Threads):10
- Ramp-Up 时间(秒):5
- 循环次数(Loop Count):1
4.3 添加 HTTP 请求
- 右键线程组 → Add → Sampler → HTTP Request
- 配置:
- 协议:https
- 服务器名称:httpbin.org
- 方法:GET
- 路径:/get
4.4 添加监听器
- 右键线程组 → Add → Listener → View Results Tree
- 右键线程组 → 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 encoding:UTF-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 Value:true
要求返回的 JSON 中 success 字段为 true。
6.4 持续时间断言(Duration Assertion)
用于校验响应时间不超过阈值:
Duration:1000 (毫秒,超过 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 中使用它。
- 在登录采样器上右键 → Add → Post Processors → Regular Expression Extractor
- 配置:
Apply to:Main sample
字段:响应文本
引用名称(Reference Name):token
正则表达式:\{"token": "(.+?)"\}
模板:1
匹配数字:1
默认值:NOT_FOUND
- 在订单请求的 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 Group:100
Timeout in milliseconds:5000
即:等 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 压测通用流程
- 先小并发冒烟,确认脚本无误
- 用少量线程 + 循环验证断言正确性
- 逐步增加线程数,观察吞吐量(TPS)与响应时间曲线
- 找到拐点: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. 最佳实践
- 不要用 GUI 压测:GUI 用于编写和调试,正式压测一律命令行(-n)。
- 必须加断言:没有断言,错误率永远是 0,结果无意义。
- 使用 HTTP Request Defaults:统一协议/服务器,减少重复配置、便于迁移环境。
- 参数化数据:用 CSV 模拟多用户,避免全部线程用同一账号导致服务端缓存干扰结果。
- 合理设置 Ramp-Up:不要 0 秒瞬间启动所有线程,除非专门测集合点。
- 分离测试环境:压测会影响被测系统性能,不要在生产直接压(除非有明确授权)。
- 先小规模验证:10 并发跑通后再放大并发。
- 监控服务端资源:结合 CPU / 内存 / 数据库连接等指标定位瓶颈,别只看 JMeter 数字。
- 保持脚本简单:优先用内置组件,JSR223 脚本(Groovy)慎用且要注意性能。
- 结果可复现:固定线程数、循环、定时器,避免用 GUI 手动点来点去。
- 不要超时中断:设置合理的连接/响应超时(如 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/\>