Gatling version: 3.13.1 (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.
NOTE: I had to remove the links from above because the system would not let me post this with them included
Hello everyone! I’ve just started exploring Gatling as a way to test a reverse proxy I am building. I have a very simple example simulation which is intended to be a stress test on the system to find the failure point. I am running this using the maven wrapper from my M1 Mackbook Pro.
if I configure Gatling for a slow enough ramp, the simulation is able to run (mostly) smoothly and get up to about 2500 TPS. At this point calls start timing out and it seems like some kind of cascade failure happens as any more users added just also time out. 2,500 tps seems quite low to me as I am able to send 20,000 TPS without issue using both wrk and vegeta.
I have set .shareConnections()
on my http protocol which helped dramatically, but I still feel like I must be approaching this the wrong way. My intuition says that I should be having each user send multiple requests rather than 1 request per user to achieve higher request volumes but from the documentation and reading other sources online it seems that 1 user/1 request is the “best practice” for Gatling.
Any input would be greatly appreciated!
ReverseProxySimulation.java
package reverseproxy;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import java.time.Duration;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class ReverseProxySimulation extends Simulation {
private static final String BASE_URL = "http://192.168.26.20/api";
private final HttpProtocolBuilder httpProtocol = http.baseUrl(BASE_URL)
.contentTypeHeader("application/json")
.shareConnections()
.asyncNameResolution();
private static final int INCREMENT = Integer.parseInt(System.getProperty("INCREMENT", "500"));
private static final int NUM_STEPS = Integer.parseInt(System.getProperty("NUM_STEPS", "4"));
private static final int STEP_TIME = Integer.parseInt(System.getProperty("STEP_TIME", "60"));
private static final int STARTING_VOLUME = Integer.parseInt(System.getProperty("STARTING_VOLUME", "2000"));
private static AtomicInteger txnIdIterator = new AtomicInteger(10000);
private static Iterator<Map<String, Object>> txnIdFeeder =
Stream.generate((Supplier<Map<String, Object>>) () -> {
return Map.of("txn_id", txnIdIterator.getAndIncrement());
}).iterator();
private static FeederBuilder.FileBased<Object> importerUUIDFeeder = jsonFile("data/importer_uuid_feed.json").random();
private static ChainBuilder sendTxn = feed(txnIdFeeder)
.feed(importerUUIDFeeder)
.exec(http("send request")
.post("/#{importer_uuid}")
.basicAuth("parse_only_user", "ABCD1234$")
.body(ElFileBody("bodies/txn_id.json"))
.requestTimeout(Duration.ofSeconds(1))
.check(status().is(200))
.check(jmesPath("\"transaction-results\".\"transaction-id\"").isEL("#{txn_id}")));
private ScenarioBuilder scn = scenario("reverse proxy test")
.exec(sendTxn);
{
setUp(
scn.injectOpen(
// rampUsersPerSec(0)
// .to(STARTING_VOLUME)
// .during(Duration.ofMinutes(5)),
incrementUsersPerSec(INCREMENT)
.times(NUM_STEPS)
.eachLevelLasting(STEP_TIME)
.separatedByRampsLasting(30)
.startingFrom(STARTING_VOLUME)
)
).protocols(httpProtocol);
}
}
txn_id.json
{
"txn_id": #{txn_id}
}
importer_uuid_feeder.json
[
{
"importer_uuid": "39e6f3b0-aa69-4b39-9037-0cb08dcf1705"
},
{
"importer_uuid": "7ea50807-0d92-4f1f-8f35-6f04b4b5955b"
}
]