JMeter初体验和坑分享

Apache JMeter - User's Manual

GUI 配置层:坑在哪里

坑 1:关联(Correlation)配置繁琐

比如典型的场景:登录返回 token,下一个请求要用这个 token。

正常写代码:

复制代码
token = login()
response = api(token)

JMeter GUI 配置:

复制代码
1. 添加 HTTP Request(登录)
2. 添加 JSON Extractor:
   - Names: token
   - JSON Path: $.data.token
   - Default Values: NOT_FOUND
3. 添加 HTTP Header Manager:
   - Header: Authorization = ${token}
4. 添加第二个 HTTP Request(业务接口)

五个组件要配,一不小心变量名拼错、JSON Path 写错,排查起来很费劲。


坑 2:参数化(CSV Data Set Config)

CSV 文件有中文/特殊字符时编码容易出问题,循环次数和线程数配合关系容易搞混。

复制代码
CSV 文件:users.csv
变量名:userId,password,amount
Delimiter:,
Recycle on EOF:True / False(到底是循环用还是停?)

这个配置理解错一个,线程组就跑出完全不同的行为。


坑 3:组件叠加后的执行顺序

JMeter 的执行顺序是:

复制代码
1. 配置元件(Config Element)先执行
2. 前置处理器
3. 定时器(每个 Sampler 前执行)
4. Sampler(发请求)
5. 后置处理器
6. 断言
7. 监听器

GUI 界面上组件是平铺排列的,但执行顺序是上述逻辑顺序,新手很容易搞混。比如想在断言里引用一个后置处理器提取的变量,但执行顺序不对,变量还没生成就开始断言了。


坑 4:版本管理困难

.jmx 文件是 XML,Git merge 时冲突基本无法自动合并,只能人工对照两份文件取舍。团队三个人同时改脚本,最后合版本靠"谁记得改了啥"。


代码层(JSR223 / BeanShell):难在哪里

难 1:JMeter API 不直观

复制代码
// JMeter 里写 Groovy 获取响应内容
def response = prev.getResponseDataAsString()  // prev 是前一个 Sampler 的 Response
def json = new groovy.json.JsonSlurper().parseText(response)
def token = json.data.token

// 引用到下一个请求
vars.put("token", token)  // vars 是 JMeter 变量容器

prevvarsctx 这些变量是 JMeter 上下文注入的,不查文档根本不知道存在。写错了没有 IDE 提示,纯靠经验。


难 2:Groovy 性能陷阱

JMeter 里写 Groovy 容易踩性能坑:

复制代码
// 慢:每次解析 JSON
def json = new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString())

// 快:复用解析器(但新手不知道)
static def slurper = new groovy.json.JsonSlurper()
def json = slurper.parseText(prev.getResponseDataAsString())

JMeter 本身就对性能敏感,Groovy 写得不讲究反而成为压测瓶颈。


难 3:异常处理缺失

JMeter 的 Groovy 脚本异常默认直接抛到日志,Sampler 标记失败但原因不直观:

复制代码
// 不会让 JMeter 报错的写法(try-catch 吞掉)
try {
    def json = new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString())
    vars.put("token", json.data.token)
} catch (Exception e) {
    // 吞掉异常,但 sampler 还是成功状态,埋雷
}

// 正确写法要手动标记失败
try {
    def json = new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString())
    vars.put("token", json.data.token)
} catch (Exception e) {
    prev.setSuccessful(false)  // 显式标记失败
    prev.setResponseData("JSON解析失败: " + e.message)
}

总结:什么时候用什么方式

场景 推荐方式
简单 HTTP 请求,单线程 GUI 配置,够用
关联多、参数多、逻辑复杂 GUI 搭框架 + JSR223 Groovy 写核心逻辑
高并发压测(性能敏感) 尽量少用 Groovy,GUI 能搞定的别用脚本
gRPC/Dubbo 等协议 自定义 Java Sampler(打包成 jar)
团队协作 脚本模块化,.jmx 拆分管理,Git 建分支

核心原则:JMeter 是配置工具,不是编程工具。能用配置解决的问题别用代码,代码层是补足协议盲区用的,不是用来写复杂逻辑的。