4. 压测脚本编写
好,咱们直接进入正题。这一章是压测脚本的「动手环节」。前面讲了理论、讲了规划,现在要落地了。我个人习惯,写脚本之前先想清楚三件事:模拟多少用户?发什么请求?怎么判断结果对不对? JMeter 里对应的就是线程组、取样器和断言。咱们一个一个来拆。
4.1 线程组:压测的「发动机」
线程组,说白了就是定义「有多少虚拟用户在跑」。你想想看,没有线程组,脚本就是个空壳。
核心配置项:
- 线程数: 模拟的用户数量。比如 100 个线程,就是 100 个虚拟用户。
- Ramp-Up 时间: 多少秒内启动完所有线程。我建议设成跟线程数差不多,比如 100 线程设 100 秒,这样用户是慢慢上来的,不会把服务器瞬间冲垮。
- 循环次数: 每个线程跑多少次脚本。勾选「永远」的话,需要手动停止。
嗯,这里要注意:线程组里有个「调度器」配置。如果你想让脚本跑 10 分钟自动停,就在调度器里设「持续时间」为 600 秒。这个比手动点停止按钮靠谱多了。
4.2 取样器:发什么请求?
取样器是真正干活的东西。HTTP 请求、JDBC 请求、Java 请求……最常用的是 HTTP 请求取样器。
HTTP 请求配置要点:
- 协议: http 或 https。注意 https 需要配证书,不然会报握手失败。
- 服务器名称或 IP: 目标地址。别写 localhost,除非你压的是本机。
- 方法: GET、POST、PUT、DELETE 等。压测接口用 POST 居多。
- 路径: 接口的具体路径,比如 /api/v1/login。
- 参数: 可以写在 URL 里,也可以写在 Body 里。我建议用 Body Data,结构清晰。
举个例子,一个登录接口的配置:
协议:https
服务器:api.example.com
方法:POST
路径:/api/v1/login
Body Data:
{
"username": "testuser",
"password": "123456"
}
我曾经遇到过一个问题:压测时发现所有请求都返回 400 错误。查了半天,原来是 Content-Type 没设成 application/json。JMeter 默认是 application/x-www-form-urlencoded,跟后端不匹配。所以记得在 HTTP 请求下面加一个 HTTP 信息头管理器,手动指定 Content-Type。
4.3 参数化:让数据「活」起来
如果所有用户都用同一个账号登录,那压测结果毫无意义。服务器可能把数据缓存了,或者把账号给封了。所以我们需要参数化——让每个虚拟用户用不同的数据。
常用参数化方式:
| 方式 | 适用场景 | 我的建议 |
|---|---|---|
| CSV 数据文件 | 大量独立数据(如 10000 个账号) | 最常用,推荐 |
| 用户自定义变量 | 少量固定数据(如服务器地址) | 适合全局配置 |
| 函数助手 | 随机数据(如随机手机号) | 临时用用可以,别依赖 |
CSV 数据文件配置步骤:
- 准备一个 CSV 文件,比如 users.csv,内容如下:
user1,pass1
user2,pass2
user3,pass3
- 在线程组上右键 → 添加 → 配置元件 → CSV 数据文件设置。
- 配置文件名、变量名(比如 username, password)、分隔符(逗号)。
- 在 HTTP 请求的 Body Data 里引用变量:
{
"username": "${username}",
"password": "${password}"
}
4.4 断言:怎么判断结果对不对?
压测跑完了,结果全是 200 OK,就代表系统没问题吗?不一定。可能接口返回了错误信息,但状态码还是 200。所以我们需要断言——验证响应内容是否符合预期。
常用断言:
- 响应断言: 检查响应文本是否包含某个字符串。比如登录成功返回 "",失败返回 "error"。
- JSON 断言: 针对 JSON 格式的响应,检查某个字段的值。比如检查 $.code 是否等于 0。
- 大小断言: 检查响应大小是否在某个范围内。可以用来检测是否返回了完整页面。
我个人最常用的是 JSON 断言。举个例子:
响应内容:
{
"code": 0,
"message": "success",
"data": {
"": "abc123"
}
}
JSON 断言配置:
Assert JSON Path expression: $.code
Expected value: 0
如果 code 不等于 0,断言就会失败,JMeter 会在结果里标记为红色。这样你一眼就能看出哪些请求有问题。
嗯,这里有个小技巧:断言失败时,JMeter 默认不会停止脚本。如果你想在断言失败后停止整个测试,可以在断言里勾选「如果断言失败,停止线程」或「停止测试」。不过要小心,生产环境压测时别乱用,否则一个失败就把整个压测停了,你半夜还得爬起来重启。
4.5 监听器:怎么看结果?
脚本写好了,跑起来了,怎么看结果?监听器就是干这个的。
常用监听器:
| 监听器名称 | 用途 | 我的建议 |
|---|---|---|
| 查看结果树 | 调试脚本时看单个请求的详情 | 调试时用,压测时关掉,否则吃内存 |
| 聚合报告 | 统计吞吐量、平均响应时间、错误率 | 压测必用,最核心的监听器 |
| 图形结果 | 可视化展示吞吐量变化趋势 | 适合做汇报,直观 |
| 后端监听器 | 将结果实时发送到 InfluxDB + Grafana | 生产环境压测推荐,实时监控 |
我刚开始做压测时,喜欢开着「查看结果树」跑压测。结果跑了 10 分钟,JMeter 直接 OOM 了。为什么?因为查看结果树会把每个请求的响应内容都存到内存里,1000 个请求还好,10 万个请求直接爆炸。所以记住:调试时用查看结果树,压测时用聚合报告。
4.6 实战:一个完整的压测脚本
咱们把上面这些串起来,写一个完整的压测脚本。假设我们要压测一个登录接口:
- 线程组: 100 线程,Ramp-Up 100 秒,循环 10 次。
- CSV 数据文件: 读取 100 个账号密码。
- HTTP 请求: POST 到 /api/v1/login,Body 里引用 ${username} 和 ${password}。
- JSON 断言: 检查 $.code 是否等于 0。
- 聚合报告: 查看吞吐量、平均响应时间、错误率。
脚本结构如下:
测试计划
├── 线程组 (100线程, Ramp-Up 100s, 循环10次)
│ ├── CSV 数据文件设置 (users.csv)
│ ├── HTTP 请求默认值 (协议、服务器地址)
│ ├── HTTP 信息头管理器 (Content-Type: application/json)
│ ├── 登录接口 (HTTP 请求)
│ │ └── JSON 断言 ($.code = 0)
│ └── 聚合报告 (监听器)
跑完之后,聚合报告里会显示:
- #样本: 1000 个请求(100 线程 × 10 次)
- 平均响应时间: 比如 120ms
- 吞吐量: 比如 800 req/s
- 错误率: 比如 0.00%
如果错误率不是 0%,那就得去排查了。可能是账号密码不对,可能是接口返回了其他错误码。这时候可以临时打开「查看结果树」,看几个失败的请求到底返回了什么。
4.7 本章知识体系
下面这张图,帮你把本章的核心逻辑串起来:
这张图展示了压测脚本的完整执行流程。从线程组开始,经过配置元件、取样器,再到断言和监听器,最后输出结果分析。每一步都有它的作用,缺一不可。
好了,这一章的内容就到这儿。脚本写好了,下一件事就是跑起来看数据。记住:脚本是工具,数据才是答案。别在脚本上花太多时间纠结,跑起来再说。