Gattle:如何在虚拟用户之间共享动态身份验证?

问题描述 投票:0回答:2

使用 Gattle(Java 中),我想对需要通过不记名令牌 (JWT) 进行身份验证的后端运行性能测试。令牌会在 5 分钟后过期,因此如果测试运行时间超过该时间(这就是目的),我需要更新它。

这就是目前的工作方式:

HttpProtocolBuilder httpProtocol = http.baseUrl("http://my.url/v1/")
    .authorizationHeader((session) -> session.getString("AuthToken"))
    .check(status().in(200, 401).saveAs("status"));

private String getAuthentication() {
  // retrieves and returns a new, valid authentication token via HttpURLConnection
  // this method has been proven to work correctly
}

ScenarioBuilder scn = scenario("My scenario")
    .repeat(100).on(
        exec(http("My HTTP call").get("/my/endpoint"))
            .pause(1)
            .doIfOrElse((session -> session.getInt("status") == 401))
            .then(
                exec(session -> {
                    System.out.println("Got status 401 - retrieving new token");
                    return session.set("AuthToken", getAuthentication());
             }))
            .orElse(
                exec(session -> {
                    System.out.println("Got status: " + session.getInt("status"));
                    return session;
                })
            )
        );

    {
        setUp(
            scn.injectClosed(
                rampConcurrentUsers(5).to(40).during(1200), constantConcurrentUsers(40).during(600))
        ).protocols(httpProtocol);
    }

我同意这个解决方案,但我发现

getAuthentication
调用发生得太频繁,导致身份验证后端被调用得比必要的更频繁。我想这是由于虚拟用户在自己的线程中运行,并且通过
session
变量进行的同步没有发生(足够快)。

那么,有没有什么聪明的方法可以在需要时只进行一次身份验证,并与所有用户共享令牌?

我想到的一些事情:

  • synchronized
    上使用
    getAuthentication
    Java 关键字 - 没有改变任何东西
  • 创建一个新的 Java 线程,该线程将每 4:30 分钟自动获取一次新的身份验证,并将新令牌写入一个变量,然后可以通过
    authorizationHeader
    调用访问该变量。还没有尝试过,因为对我来说这似乎是一个相当糟糕的解决方案。

我一直在四处寻找,似乎还有更多人面临同样的挑战,但我还没有找到任何适用的解决方案。

额外问题:有什么办法可以不将 401 回复计入最终统计数据中吗? :)

提前非常感谢!

java authentication jwt performance-testing gatling
2个回答
2
投票

从 Gattle 自己的线程执行一些阻塞操作(UrlConnection、synchronized)是一个非常非常糟糕的主意。你会让整个引擎熄火。

相反,您应该按照后台任务中所述抢先更新共享令牌:

  • 如果您想坚持阻塞 UrlConnection,则可以使用专用 Java 线程
  • 或者如果您愿意放弃 UrlConnection,则可以使用独特的加特林场景。

注意:这个问题已在 Gattle 社区论坛 上被问过多次,您会在那里找到后一种解决方案的一些示例。


0
投票

感谢 Stéphane Landelle 和下面提到的来源,这就是我现在的具体实现:

public class MySimulation extends Simulation {

    protected volatile String token = "";

    protected HttpProtocolBuilder httpProtocol = http
        .baseUrl(myBaseUrl)
        .authorizationHeader((session) -> {
            return "Bearer " + token;
        })
        .check(status().in(200, 401));

    // Retrieving a new token
    ScenarioBuilder getToken = scenario("Acquire JWT")
        .exec(
            http("get token")
                .post(myAuthEndpoint)
                .body(myAuthBody)
                .check(
                    bodyString().find().transform(bodyString -> {
                        // extract auth token from response
                    })
                    .saveAs("AuthToken")
                )
            ).exitHereIfFailed()
        .exec(session -> {
            token = session.getString("AuthToken");
            return session;
        }).pause(Duration.ofSeconds(270)); // renew token every 4 minutes and 30 seconds

    // The actual load test
    ScenarioBuilder scn = scenario("My scenario")
        .exec(http("My scenario")
            .get("/my/endpoint/with/parameters")
            .check(jsonPath(myJsonPath).ofString().is(whatIExpect)));

    // Start token retrieving alongside the actual load test
    {
        setUp(
            getToken.injectClosed(rampConcurrentUsers(1).to(1).during(1800)),
            scn.injectClosed(rampConcurrentUsers(5).to(40).during(1200),
                constantConcurrentUsers(40).during(600))
        ).protocols(httpProtocol);
    }
}

可能有更优雅的解决方案,但这应该是如何实现它的第一个草图。关键是与“真实”测试并行运行

getToken
场景,使其暂停时间比令牌有效性稍短一点,并相应地更新令牌。 (这里token有效期为300秒,“获取JWT”场景每270秒运行一次。)

“获取令牌”需要与真实负载测试场景一样长地运行。 (嗯 - 根本不是。做一些算术,可以省略最后一次不必要的运行,从而缩短整个测试的持续时间。但对于我的情况来说,这已经足够了。)


有用的来源:

在加特林负载测试期间刷新承载令牌

https://community.gadling.io/t/global-shared-token-is-populated-blank/8007/5

https://community.gadling.io/t/gadling-token-service-and-struct-of-simulation/1535/13

https://community.gadling.io/t/how-to-execute-the-first-request-only-once/6063/5

© www.soinside.com 2019 - 2024. All rights reserved.