如何在Gatling的Scala多仿真文件间共享Session变量?
Gatling跨仿真文件复用OrderId的解决方案
核心结论
Gatling中通过session => session.setAll()设置的Session完全无法跨仿真文件访问——每个仿真文件运行时拥有独立的JVM上下文,Session是单个虚拟用户的私有临时数据,仿真之间完全隔离,不存在跨文件共享的机制。
可行解决方案
1. 预生成订单数据并通过CSV复用(优化你尝试过的方案)
- 步骤1:单独生成订单数据
写一个独立的Scala程序或Gatling单场景仿真,仅调用一次订单API生成OrderId和OrderUri,将结果写入CSV文件,格式如下:orderId,orderUri O12345,/api/orders/O12345 - 步骤2:在目标仿真中读取CSV
在需要复用数据的仿真文件中,使用Gatling的Feeder读取CSV,确保所有虚拟用户复用预生成的数据:val orderFeeder = csv("pre_generated_orders.csv").circular // 循环复用,适合允许重复使用订单的场景 // 若订单只能用一次,改用.queue val scn = scenario("Reuse Order") .feed(orderFeeder) .exec(http("Use Order") .get("${orderUri}") .header("Order-Id", "${orderId}")) - 适用场景:分布式压测、需要多组订单数据、数据需持久化的场景。
2. Scala全局单例对象存储(仅适合本地单机压测)
- 步骤1:创建全局单例
在项目中定义一个线程安全的单例对象,用于存储生成的订单数据:object SharedOrderData { @volatile private var _orderId: String = "" @volatile private var _orderUri: String = "" def setOrderData(id: String, uri: String): Unit = { _orderId = id _orderUri = uri } def orderId: String = _orderId def orderUri: String = _orderUri } - 步骤2:第一个仿真写入数据
在生成订单的仿真中,确保仅执行一次API调用并写入单例:class GenerateOrderSimulation extends Simulation { val scn = scenario("Generate Order") .exec(http("Create Order") .post("/api/orders") .check(jsonPath("$.orderId").saveAs("orderId"), jsonPath("$.orderUri").saveAs("orderUri"))) .exec(session => { SharedOrderData.setOrderData(session("orderId").as[String], session("orderUri").as[String]) session }) .oncePerScenario // 确保整个仿真仅执行一次订单生成逻辑 setUp(scn.inject(atOnceUsers(1))) } - 步骤3:第二个仿真读取数据
在复用数据的仿真中,直接从单例读取并设置到Session:class ReuseOrderSimulation extends Simulation { val scn = scenario("Reuse Order") .exec(session => session.setAll("orderId" -> SharedOrderData.orderId, "orderUri" -> SharedOrderData.orderUri)) .exec(http("Use Order") .get("${orderUri}") .header("Order-Id", "${orderId}")) setUp(scn.inject(rampUsers(100) during (10 seconds))) } - 注意:此方案仅适用于本地单机压测,分布式集群环境下单例对象无法跨节点共享。
3. 仿真启动前预生成数据(用before钩子)
在需要复用数据的仿真中,重写before方法,在仿真启动前调用一次订单API生成数据,避免依赖其他仿真:
class ReuseOrderSimulation extends Simulation { private var orderId: String = _ private var orderUri: String = _ override def before { // 用普通HTTP客户端(如Apache HttpClient)调用订单API,不要用Gatling DSL(before是仿真启动前的初始化逻辑) val httpClient = HttpClientBuilder.create().build() val request = new HttpPost("http://your-api-host/api/orders") val response = httpClient.execute(request) val responseBody = EntityUtils.toString(response.getEntity) // 解析JSON获取数据(可使用Jackson等库) orderId = // 解析responseBody得到orderId orderUri = // 解析responseBody得到orderUri } val scn = scenario("Reuse Order") .exec(session => session.setAll("orderId" -> orderId, "orderUri" -> orderUri)) .exec(http("Use Order") .get("${orderUri}") .header("Order-Id", "${orderId}")) setUp(scn.inject(atOnceUsers(50))) }
- 适用场景:无需依赖其他仿真,单独运行即可复用订单数据的本地压测场景。
方案选型建议
- 分布式压测:优先选CSV文件复用,将CSV放在共享存储目录供所有节点读取。
- 本地单机压测:选全局单例或before钩子,实现简单且性能损耗低。
- 订单不可重复使用:用CSV的
.queue模式,确保每个订单仅被一个虚拟用户使用。
内容的提问来源于stack exchange,提问作者Banu
相关产品推荐
相关产品推荐

