4. 逻辑控制器:IF控制器、While控制器、ForEach控制器、循环控制器、交替控制器、随机控制器

逻辑控制器是JMeter脚本编排的核心组件,用于控制采样器(Sampler)的执行顺序、次数与条件。在容量压测与巡检自动化场景中,合理使用逻辑控制器可以大幅减少脚本冗余,实现动态参数传递与流量模拟。本章逐一拆解六种常用逻辑控制器的配置要点、适用场景与避坑指南。

核心原则:逻辑控制器只控制其子节点的执行逻辑,不发送请求。所有控制器均需配合采样器或其它控制器使用。

4.1 IF控制器(If Controller)

IF控制器根据条件表达式决定是否执行其子节点。支持JMeter内置函数与变量判断,是条件分支的核心工具。

配置项 说明 示例
Condition (default) JavaScript或__jexl3/groovy表达式 ${__jexl3(${count} > 5,)}
Interpret Condition as Variable Expression 勾选后直接使用变量值(true/false) ${is_active}
Evaluate for all children 每次子节点执行前重新评估条件 默认勾选
常见陷阱:使用JavaScript模式时,变量引用需用vars.get("count"),而非${count}。推荐使用__jexl3或__groovy函数,性能更优且避免JS引擎差异。
// 推荐写法:使用__jexl3函数
${__jexl3("${response_code}" == "200" && ${latency} < 1000,)}

// 变量表达式模式(勾选Interpret Condition as Variable Expression)
${is_success}

4.2 While控制器(While Controller)

While控制器在条件为真时持续循环执行子节点,直到条件变为假或达到最大循环次数。常用于等待异步响应、轮询状态或重试机制。

  • 条件语法:支持${__jexl3(...)}、${__groovy(...)}或直接变量判断。
  • 空条件:留空时无限循环(需配合${__javaScript(...)}或手动中断)。
  • 退出机制:在子节点中通过vars.put("continue_flag", "false")改变条件变量。
// While条件示例:等待订单状态变为"SUCCESS"
${__jexl3("${order_status}" != "SUCCESS",)}

// 子节点中设置退出条件(使用JSR223 PostProcessor)
vars.put("order_status", prev.getResponseDataAsString());
巡检场景:在巡检脚本中,While控制器可用于等待容器启动完成或服务健康检查通过,避免固定等待时间造成的资源浪费。

4.3 ForEach控制器(ForEach Controller)

ForEach控制器遍历用户定义的变量数组,为每个元素执行一次子节点。是参数化批量操作的利器,尤其适合从CSV或用户自定义变量中读取列表数据。

配置项 说明 示例
Input variable prefix 变量前缀,如user_id user_id
Start index 起始索引(从0开始) 0
End index 结束索引(包含) ${user_id_n}
Output variable name 当前元素存储的变量名 current_user
// 变量定义(User Defined Variables或CSV Data Set Config)
user_id_0 = 1001
user_id_1 = 1002
user_id_2 = 1003
user_id_n = 2

// ForEach控制器内引用
${current_user}  // 依次输出1001, 1002, 1003

4.4 循环控制器(Loop Controller)

循环控制器是最基础的重复执行控制器,固定循环次数或永久循环。适用于压力测试中模拟持续请求、重复数据准备等场景。

  • Loop Count:设置循环次数,输入-1或勾选Forever表示无限循环。
  • 与线程组循环的区别:线程组循环控制整个线程的执行次数,循环控制器仅控制其子节点。
  • 嵌套使用:可嵌套在While或IF控制器内部,实现复杂循环逻辑。
// 循环控制器配置示例
Loop Count: 10
// 子节点:HTTP请求 + 固定定时器(1000ms)
// 效果:连续发送10次请求,每次间隔1秒

4.5 交替控制器(Interleave Controller)

交替控制器每次执行时,按顺序轮流选取一个子节点执行,跳过其余子节点。适用于模拟用户交替操作、轮询不同接口或A/B测试场景。

配置项 说明 行为
Interleave across threads 勾选后跨线程交替 线程1执行子节点1,线程2执行子节点2
忽略子控制器 不勾选时,子控制器整体视为一个节点 交替粒度更粗
// 交替控制器子节点结构
├── Interleave Controller
│   ├── HTTP Request - 登录
│   ├── HTTP Request - 查询订单
│   └── HTTP Request - 提交表单
// 执行顺序:登录 → 查询订单 → 提交表单 → 登录 → ...

4.6 随机控制器(Random Controller)

随机控制器每次执行时,从其子节点中随机选取一个执行。适用于模拟用户随机行为、随机流量分布或异常场景注入。

  • 随机策略:每次独立随机,不保证均匀分布。
  • 与交替控制器的区别:交替控制器按固定顺序轮流,随机控制器完全随机。
  • 权重模拟:可通过重复子节点数量间接控制概率(如子节点A出现2次,B出现1次,则A概率约67%)。
// 随机控制器子节点结构
├── Random Controller
│   ├── HTTP Request - 浏览首页(权重高:重复2次)
│   ├── HTTP Request - 浏览首页
│   ├── HTTP Request - 搜索商品
│   └── HTTP Request - 查看详情
// 执行概率:浏览首页约50%,搜索25%,查看详情25%

4.7 逻辑控制器对比与选型

控制器 核心逻辑 适用场景 循环次数
IF控制器 条件判断 分支执行、异常处理、动态跳过 0或1次
While控制器 条件循环 轮询、重试、等待异步完成 动态(条件控制)
ForEach控制器 遍历数组 批量参数化、列表处理 数组长度
循环控制器 固定次数循环 重复请求、压力测试 固定值或无限
交替控制器 轮流执行 交替操作、A/B测试 子节点数
随机控制器 随机选取 模拟随机行为、流量分布 1次(随机选1)
逻辑控制器执行流程对比图 线程组入口 逻辑控制器(控制子节点执行逻辑,不发送请求) IF控制器 条件判断 While控制器 条件循环 ForEach控制器 遍历数组 循环控制器 固定次数 交替控制器 轮流执行 随机控制器 随机选取 采样器(Sampler):HTTP请求、JDBC请求、Java请求等 循环/While/ForEach回退 结果处理:断言 / 提取器 / 监听器 说明 逻辑控制器仅控制子节点执行逻辑,不发送请求;可嵌套组合使用实现复杂场景

4.8 组合使用实战:巡检自动化参数配置

在容量压测巡检脚本中,逻辑控制器常组合使用以实现动态参数配置与自适应执行。以下是一个典型组合结构:

// 巡检脚本逻辑控制器组合示例
├── Thread Group
│   ├── User Defined Variables(定义巡检参数列表)
│   │   ├── service_id_0 = svc-001
│   │   ├── service_id_1 = svc-002
│   │   ├── service_id_2 = svc-003
│   │   └── service_id_n = 2
│   ├── ForEach Controller(遍历服务列表)
│   │   ├── Input variable prefix: service_id
│   │   ├── Output variable name: current_service
│   │   ├── While Controller(健康检查轮询,最多重试5次)
│   │   │   ├── Condition: ${__jexl3("${health_status}" != "UP" && ${retry_count} < 5,)}
│   │   │   ├── HTTP Request - 健康检查接口
│   │   │   ├── JSR223 PostProcessor(更新health_status和retry_count)
│   │   │   └── Loop Controller(重试间隔1秒)
│   │   │       └── Constant Timer(1000ms)
│   │   ├── IF Controller(健康检查通过后执行)
│   │   │   ├── Condition: ${__jexl3("${health_status}" == "UP",)}
│   │   │   ├── HTTP Request - 业务接口1
│   │   │   ├── HTTP Request - 业务接口2
│   │   │   └── Random Controller(随机执行一个扩展检查)
│   │   │       ├── HTTP Request - 慢查询检查
│   │   │       └── HTTP Request - 缓存命中检查
│   │   └── Interleave Controller(交替记录日志到不同文件)
│   │       ├── JSR223 Sampler - 写入日志文件A
│   │       └── JSR223 Sampler - 写入日志文件B
巡检自动化要点:通过ForEach遍历服务列表,While实现自适应重试,IF控制条件分支,Random注入随机检查,Interleave分散日志写入压力。这种组合结构可大幅提升巡检脚本的健壮性与可维护性。

4.9 性能与调试建议

  • 避免深层嵌套:逻辑控制器嵌套超过3层时,脚本可读性下降且调试困难。建议将复杂逻辑拆分为多个线程组或模块。
  • 条件表达式性能:优先使用__jexl3或__groovy,避免JavaScript模式(每次评估需启动JS引擎)。
  • 变量作用域:ForEach控制器输出的变量仅在当前线程组内有效,跨线程组传递需使用${__setProperty()}或属性。
  • 调试技巧:在逻辑控制器下添加Debug Sampler或JSR223 Sampler输出变量值,配合View Results Tree监听器快速定位问题。
容量压测特别提醒:While控制器在条件永不满足时会导致无限循环,压测前务必设置最大循环次数或超时机制。建议在While子节点中加入计数器变量,达到阈值后强制退出。