Gatling version: 3.11.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.
Hi Gatling Community,
I continue here with my attempts at the load modelling that I started in another thread.
In short I want to have stepped load with regular ramp up phases evenly spreading the users and only adding the new ones. I also want the users to be the “returning users” and therefore not opening a new connection to the system on each scenario iteration. And I want to pace the duration of the scenario iterations (the tested search request executes very fast ~30 ms).
I could do that with the code presented below. I am quite happy with the results
I have regular ramp-ups, the requests are evenly spread out, the users “return” with each scenario iteration. As one can see around 20:20, I was able to find the throughput limit of the tested system.
So far so good, but here comes the nitpicking . This load profile is created using one scenario per each load step, so I end up with 22 scenarios and this has its consequences
- Look at the left graph above, the list of scenario names covers a part of the image… a bit unreadable.
- The console output shows the progress of all the 22 populations every 5 seconds, that is hardly readable. In abstract terms I would prefer to think that I have just a single population of users that grows…
- And lastly, since I configured logging to a file, my logs are filled with the below information, just endless entries telling me that a Scenario has finished injecting. Once would be enough.
3813870 [GatlingSystem-akka.actor.default-dispatcher-8] INFO i.g.c.c.inject.open.OpenWorkload - Scenario io.gatling.core.scenario.Scenario@5c892028 has finished injecting
3813870 [GatlingSystem-akka.actor.default-dispatcher-8] INFO i.g.c.c.inject.open.OpenWorkload - Scenario io.gatling.core.scenario.Scenario@3487f356 has finished injecting
...
Altogether I can do what I need to, but sometimes it feels like it is unnecessary difficult. I am not actually sure if there are better ways to create the desired load with Gatling or if it just wasn’t designed to fit my particular needs.
I already have an idea how I could achieve this load profile with just a single scenario… it will be even more complicated… I might be back once I get there…
In the meantime I would be grateful for any ideas that simplify my solution.
import static com.load.RegularSteppedLoad.regularSteppedLoad;
...
{
setUp(
regularSteppedLoad(staticSearch)
.scenarioName("StaticSearchScenario")
.paceMinMillis(987)
.paceMaxMillis(1013)
.startingFrom(0)
.incrementUsers(5)
.times(22)
.separatedByRampsLastingSec(1)
.eachLevelLastingSec(5 * 60)
.build()
).protocols(httpProtocol);
}
which uses the below class
package com.load;
import io.gatling.javaapi.core.*;
import static io.gatling.javaapi.core.CoreDsl.*;
...
public class RegularSteppedLoad {
private String scenarioName = "Scenario";
private ChainBuilder chain;
private long paceMinMillis = 1000;
private long paceMaxMillis = 1000;
private int times = 1;
private int incrementUsers = 1;
private int startingFrom = 0;
private long separatedByRampsLastingSec = 1;
private long eachLevelLastingSec = 10;
public static RegularSteppedLoad regularSteppedLoad(ChainBuilder chain) {
return new RegularSteppedLoad().chain(chain);
}
public List<PopulationBuilder> build() {
return IntStream.range(0, times).mapToObj(this::loadStepPopulation)
.collect(Collectors.toCollection(LinkedList::new));
}
private PopulationBuilder loadStepPopulation(final int stepIdx) {
return createScenarioWrapWithDurationPace(
scenarioName + "-" + stepIdx,
chain,
(long) (times - stepIdx) * (separatedByRampsLastingSec + eachLevelLastingSec),
paceMinMillis, paceMaxMillis
).injectOpen(
nothingFor(stepIdx * (separatedByRampsLastingSec + eachLevelLastingSec)),
rampUsers(stepIdx == 0 ? startingFrom + incrementUsers : incrementUsers).during(separatedByRampsLastingSec)
);
}
private ScenarioBuilder createScenarioWrapWithDurationPace(String scenarioName, ChainBuilder chain, long duringSec,
long paceMinMillis, long paceMaxMillis) {
return scenario(scenarioName)
.during(duringSec).on(
pace(Duration.ofMillis(paceMinMillis), Duration.ofMillis(paceMaxMillis))
.exec(chain)
);
}
public RegularSteppedLoad scenarioName(String scenarioName) {
this.scenarioName = scenarioName;
return this;
}
private RegularSteppedLoad chain(ChainBuilder chain) {
this.chain = chain;
return this;
}
public RegularSteppedLoad paceMinMillis(long paceMinMillis) {
this.paceMinMillis = paceMinMillis;
return this;
}
public RegularSteppedLoad paceMaxMillis(long paceMaxMillis) {
this.paceMaxMillis = paceMaxMillis;
return this;
}
public RegularSteppedLoad times(int times) {
this.times = times;
return this;
}
public RegularSteppedLoad incrementUsers(int incrementUsers) {
this.incrementUsers = incrementUsers;
return this;
}
public RegularSteppedLoad startingFrom(int startingFrom) {
this.startingFrom = startingFrom;
return this;
}
public RegularSteppedLoad separatedByRampsLastingSec(long separatedByRampsLastingSec) {
this.separatedByRampsLastingSec = separatedByRampsLastingSec;
return this;
}
public RegularSteppedLoad eachLevelLastingSec(long eachLevelLastingSec) {
this.eachLevelLastingSec = eachLevelLastingSec;
return this;
}
}
Regards,
Tomasz G.