You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JMeter多线程组ID共享与分配场景实现求助

Hey Patrick, 我来帮你搞定这个JMeter的场景难题,同时也会对比下Gatling的方案,方便你做工具选择:

JMeter解决方案

一、线程组1:批量保存生成的100+ID

你之前用${__setProperty(Id, ${Id})}只能存单个ID,因为每次调用都会覆盖旧值,所以得换两种靠谱的方式来存批量ID:

方式1:写入本地文件(适合ID数量大、需要持久化的情况)

用JSR223 PostProcessor(比BeanShell性能更好),每次生成ID后追加到文件里。把它挂在生成ID的POST请求下面,代码如下:

// 获取当前请求生成的ID
String currentId = vars.get("Id");
// 追加写入到指定文件(路径可以自定义)
FileWriter writer = new FileWriter("generated_ids.txt", true);
writer.write(currentId + System.lineSeparator()); // 每个ID占一行
writer.close();

⚠️ 一定要记得在测试计划的「测试计划设置」里勾选Run thread groups consecutively(顺序执行线程组),不然线程组2会在组1生成完所有ID前就启动,导致读不到完整的ID列表。

方式2:存入全局内存集合(适合性能要求高、不需要持久化的情况)

同样用JSR223 PostProcessor,把ID存到JMeter的全局属性列表里,这样所有线程组都能访问:

String currentId = vars.get("Id");
// 从全局属性里取ID列表,没有就新建一个
List<String> idList = props.get("idList");
if (idList == null) {
    idList = new ArrayList<>();
    props.put("idList", idList);
}
idList.add(currentId);

二、线程组2:给10个用户按规则分配ID

线程组2设置10个线程(用户),每个用户需要取10个ID。我们可以用JSR223 PreProcessor在用户发起请求前,计算好当前用户要使用的ID范围:

如果用内存集合存储ID:

把这个PreProcessor放在线程组2的第一个请求前面,代码如下:

// 获取全局的ID列表
List<String> idList = props.get("idList");
// JMeter的线程号从0开始,所以+1转成从1开始的用户编号
int userNum = ctx.getThreadNum() + 1;
// 计算当前用户的ID范围:用户1取0-9,用户2取10-19,以此类推
int startIdx = (userNum - 1) * 10;
int endIdx = userNum * 10 - 1;
// 提取对应范围的ID,存到当前线程的变量里
List<String> userSpecificIds = idList.subList(startIdx, endIdx + 1);
// 可以存成逗号分隔的字符串,或者单个变量
vars.put("userIds", String.join(",", userSpecificIds));
// 也可以把每个ID单独存为userId_1、userId_2...方便请求调用
for (int i = 0; i < userSpecificIds.size(); i++) {
    vars.put("userId_" + (i+1), userSpecificIds.get(i));
}

之后你在请求里就可以用${userId_1}、${userId_2}这样的变量来调用对应的ID了。

如果用文件存储ID:

先在线程组2的最前面加一个JSR223 Test Element,把文件里的ID读取到全局集合:

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

List<String> idList = Files.readAllLines(Paths.get("generated_ids.txt"));
props.put("idList", idList);

然后再用上面的分配逻辑即可。

JMeter vs Gatling 工具对比

JMeter的优劣势

  • ✅ 优势:可视化界面友好,你已经有了部分实现,上手调试快;社区资源丰富,遇到问题容易找到解决方案;HTTP请求的断言、处理器等生态成熟。
  • ❌ 劣势:高并发场景下性能不如Gatling;复杂逻辑的脚本维护,不如代码式的Gatling灵活。

Gatling的解决方案(代码式更简洁)

Gatling用Scala/Java编写脚本,处理这种批量生成+分配的场景会更丝滑:

  1. 生成ID:用单用户发送POST请求,提取ID并存入全局序列
  2. 分配ID:10个用户分别按索引范围取10个ID
  3. 简化版代码示例:
import io.gatling.core.Predef._
import io.gatling.http.Predef._

val generateIdsScenario = scenario("Generate 100+ IDs")
  .exec(http("Generate Single ID")
    .post("/your-generate-id-api")
    .check(jsonPath("$.id").saveAs("currentId")))
  .exec { session =>
    val existingIds = session("idList").asOption[Seq[String]].getOrElse(Seq.empty)
    session.set("idList", existingIds :+ session("currentId").as[String])
  }

val useIdsScenario = scenario("Use IDs per User")
  .exec { session =>
    val userNum = session.userId // Gatling用户ID从1开始
    val allIds = session("idList").as[Seq[String]]
    val userIds = allIds.slice((userNum-1)*10, userNum*10)
    session.set("userIds", userIds)
  }
  .repeat(10) { idx =>
    exec(http("Use ID ${userIds(" + idx + ")}")
      .get("/your-use-id-api/${userIds(" + idx + ")}"))
  }

setUp(
  generateIdsScenario.inject(atOnceUsers(1)) // 1个用户生成所有ID
    .andThen(
      useIdsScenario.inject(atOnceUsers(10)) // 10个用户分别用10个ID
    )
)
  • ✅ Gatling优势:性能碾压JMeter,适合高并发场景;代码式脚本更适合复杂逻辑的长期维护;支持更灵活的用户行为编排。
  • ❌ Gatling劣势:需要掌握Scala/Java语法,学习曲线比JMeter陡;没有可视化界面,调试依赖日志和控制台输出。
总结

如果你的并发需求不是特别高,且更倾向于可视化调试、快速完成现有脚本的改造,JMeter完全能满足你的需求;如果追求极致性能、或者需要长期维护复杂测试逻辑,Gatling会是更优的选择。

内容的提问来源于stack exchange,提问作者Patrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:46:23