Help Needed with Active Users and Throughput Configuration in Gatling (Java)

Gatling version: 3.9.5 (must be up to date)
Gatling flavor: java kotlin scala javascript typescript
Gatling build tool: maven gradle sbt bundle npm

I read the guidelines and how to ask a question topics.
I provided a SSCCE (or at least, all information to help the community understand my topic)
I copied output I observe, and explain what I think should be.

Hello Gatling Community,

I’m working on a performance testing scenario using Gatling in Java and encountering some issues. My goal is to test an API with a constant throughput of 500 requests per second (RPS) using a fixed number of users. However, the results show an unexpectedly high number of active users. I’m looking for guidance to address this issue and properly configure my test.

Current Scenario Setup

Here’s the setup I’m using in Java:
import io.gatling.javaapi.core.CoreDsl;
import io.gatling.javaapi.http.HttpDsl;
import io.gatling.javaapi.core.ScenarioBuilder;
import io.gatling.javaapi.core.PauseBuilder;
import io.gatling.javaapi.core.inject.InjectionStep;
import io.gatling.javaapi.core.inject.OpenInjectionStep;
import io.gatling.javaapi.core.Predef;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

import java.time.Duration;

public class MySimulation extends Simulation {

    HttpProtocolBuilder httpProtocol = http
        .baseUrl("http://your-api-endpoint.com") // Change to your API endpoint

    ScenarioBuilder scn = scenario("Transaction Test")
        .exec(
            http("Create Transaction Request")
                .post("/create-transaction") // Change to your API endpoint
                .check(status().is(200)) // Add any checks you need
        );

    setUp(
        scn.injectOpen(
            rampUsersPerSec(5).to(100).during(Duration.ofMinutes(3)),
            constantUsersPerSec(100).during(Duration.ofMinutes(25)),
            rampUsersPerSec(100).to(1).during(Duration.ofMinutes(2))
        ).protocols(httpProtocol)
    );
}

Issues Faced

  1. Unexpected Active User Count: The active user count in my results has reached around 20,000 users, which is much higher than expected. What could be causing this high number of active users, and how can I adjust my scenario to prevent this?
  2. Throughput and User Configuration: Given that my goal is to achieve a constant throughput of 500 RPS with 100 users, is my use of constantUsersPerSec and rampUsersPerSec configured correctly? Should I use different injection profiles or configurations to better achieve my target RPS?
  3. Best Practices: What are the best practices for configuring load tests to achieve a specific RPS with a fixed number of users? How can I manage active users more effectively to ensure accurate performance testing?

I would appreciate any advice or recommendations to help me refine my scenario and meet my performance testing goals.

Thank you!

Hi @helario,
Let’s see if I can clarify some things for you. Let’s start with a realization that the term “user” in the area of load testing has a variety of possible meanings and is a source of countless misunderstandings. Let’s see if you can describe your “users” and what they do more precisely.

  • The MySimulation system you presented processes 100*25*60=150’000 users in 25 minutes (plus ramp up and ramp down). That is a fixed number of users that your system processes (possibly with the rate of 100 u/s, if your system can cope with that) and they are all rather short-lived performing just one iteration of the load scenario (equivalent in your case to a single request) and going away. Apparently, given your system’s response times, 20’000 out of your 150’000 users are active at a given time. In summary, you have a fixed number of users, as you want, that only live to perform a single iteration of the scenario.

  • Now, why would you want to prevent it? Is the fixed number of 150’000 users too high for you? Let’s look at your other requirements, you say you would actually prefer to only work with 100 users with the rate of 500 req/s (I actually strongly prefer to talk about the rate measured in iteration/s instead). There is more than one way to achieve that and you would need to pick one that suits your use case best.

  • This would be one way to do that (which might not suite you)
    rampUsers(100).during(Duration.ofMillis(200))
    This gives exactly 100 users, again short-lived ones, which send 100 requests with the rate of 500 req/s. We don’t know when the responses arrive, but one could assume that your entire test is going to complete rather quickly.

  • Another way would be to assume the following: your users are long-lived (a single user is capable of executing multiple iterations of the load scenario), your users can complete a single iteration (in your case equivalent to a request) in the time under 200 ms and your users can work in a regular paced manner, starting an iteration every 200 ms.

    ScenarioBuilder scn = scenario("Transaction Test")
      .forever.on(
        pace(Duration.ofMillis(200))
          .exec(http(...)...)
      );
    ...
    setUp(
      scn.injectOpen(
        atOnceUsers(100)
      )...
    ).maxDuration(Duration.ofMinutes(25));
    

    This will give you a “marching elephants” load profile :slight_smile:. Is this closer to what you need? Do these assumptions match your load model?

  • If you don’t like elephants marching you can try this instead of atOnceUsers
    rampUsers(100).during(Duration.ofMillis(200))

  • You might want to vary the pacing to introduce a bit of chaos.

  • Yet another way you can learn about under this documentation link Shaping Throughput.

  • There are other possibilities (eg.: What if the average response time of the tested request is ~1s? What if the users don’t work in a paced manner and start the next iteration as soon as the current one is complete?) but let’s stop here for now.

Regards,
Tomasz G.

For fixed number of User, you have to use Closed Workload model, using open workload will keep sending a fixed number of users in 1 second, which will result in high total User there.
If your Scenario is 1 request only, you can try throttle, else I’m not sure the way to calculate yet…

Thanks @tgrzej-avaloq and @trinp
In my case, The api request is suppose to respond quickly, however, at such high throughput we are seeing some application bottleneck (application become unresponsive). When this happens, as we are using open model, Gatling tries to maintain a throughput of 100 Requests per second by increasing the count of active users.
In our case we don’t care about users as long as we are able to keep constant throughput on the API at 100 requests per seconds.
I am not sure what load model is best suited for such requirement.
We have tried using the fixed number of users like below:

public ScenarioBuilder getScnCreateTransaction() {
        ScenarioBuilder scenarioBuilder;
scenario("Create Transactions Scenario").forever().on(exec(create-transaction().pause(5)
                .exitHereIfFailed()));
        return scenarioBuilder;
    }

                setUp(scenario.getScnCreateTransaction().injectOpen(rampUsers(1000).during(Duration.ofSeconds(10))))
                        .maxDuration(Duration.ofMinutes(25))
                         .throttle(
                                 jumpToRps(100),
                                 holdFor(Duration.ofMinutes(3))
                         )

Hi @helario,
Some points to mention

  • Looking at the code you provide I can see that you creatively combined the long-living users (point #4 on my previous list) with the throughput throttling (point #7 on my previous list). I feel like you might be the only person in the world to ever try this approach. Logically you are yourself now the only expert to consult on it.

  • I would suggest that you try the combined points #4 and #5 from my previous list, but that is entirely on you.

  • In our case we don’t care about users as long as we are able to keep constant throughput on the API at 100 requests per seconds.

    It is a very peculiar requirement that you have. Of course you can create constant load by using constantUsersPerSec(100) and short-living users. Since you also write that your system cannot properly handle that load I see two possibilities: your request will fail fast and you will see an error rate close to 100% or otherwise your system might give you longer and longer responses (or timeouts), which will cause a growing queue in the load generator process, which will eventually run out of memory.

Good luck!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.