In the previous post, we automated our tests in a pipeline. This is the last post in the series, and it covers two things that only really become relevant once a framework has been running for a while. Outgrowing a single machine, and keeping the whole thing maintainable months after the initial build.
When One Machine Is Not Enough
Gatling’s engine is efficient, and a single reasonably sized machine can simulate a genuinely large number of virtual users before it becomes the bottleneck rather than the system under test. That said, at some point, usually when you are stress testing a system designed for very high real world traffic, the load generator itself becomes the limiting factor, not the application you are trying to test.
The first sign of this is usually the load generator’s own resource usage. If CPU or network throughput on the machine running Gatling is maxed out while the application under test still has headroom, you are no longer measuring the application’s limits, you are measuring your own load generator’s limits.
Splitting Load Across Multiple Machines
The most straightforward way to scale beyond one machine is to run the same simulation from several machines at once, each generating a portion of the total intended load, and combine the results afterward.
public static int totalUsersPerSec() {
return Integer.parseInt(System.getProperty("targetUsersPerSec", "100"));
}
public static int nodeCount() {
return Integer.parseInt(System.getProperty("nodeCount", "4"));
}
public static int usersPerSecForThisNode() {
return totalUsersPerSec() / nodeCount();
}
setUp(
checkoutScenario.injectOpen(
constantUsersPerSec(EnvironmentConfig.usersPerSecForThisNode())
.during(Duration.ofMinutes(15))
)
).protocols(httpProtocol);
Run the same simulation on four separate machines, each configured with nodeCount=4, and together they produce the combined target load, each one only responsible for a quarter of it. This keeps every individual load generator comfortably within its own capacity.
Gatling Enterprise, the commercial offering built on top of the open source engine, handles this kind of distributed orchestration and result aggregation for you directly, including automatically merging reports from every injector into a single unified view. For a self managed setup without that product, running several CI jobs in parallel, each targeting its share of the load, and then manually comparing or combining the resulting reports, is a reasonable and common approach for teams that only occasionally need this level of scale.
Long-Term Maintenance Habits
A framework that works well on day one can still quietly rot over months of active development, the same as any other codebase. A handful of habits keep a Gatling and Java framework healthy well after the initial build.
Treat simulation code with the same standards as production code. Code review for new scenarios, consistent naming for requests so reports stay readable, and the same linting and formatting tools you would already use on any other Java module in the codebase.
Keep test data and configuration close to where they are used, not scattered across the repository. We set this up back in part one with a clear folder structure, and it is worth periodically checking that new simulations and scenarios still follow it, since drift tends to creep in as different people add things under time pressure.
Review your assertions periodically, not just when they are first written. An SLA that made sense against last year’s infrastructure and traffic levels might be too lenient or too strict against a system that has scaled up or been re architected since. Revisit the thresholds from part nine on a regular cadence, alongside whatever the current production monitoring data actually shows.
Retire scenarios that no longer reflect real usage. If analytics show a feature is barely used anymore, a scenario built entirely around it is spending your test run’s time and your load generator’s capacity on something that no longer matters. Performance testing time is a finite resource on any given run, and it deserves to be spent where real traffic actually goes.
Wrapping Up the Series
Over these twelve posts, we went from an empty folder to a real Gatling and Java performance testing framework. Project setup, the Java DSL, injection profiles, feeders, correlation and authentication, checks that catch genuine failures, realistic scenario pacing, the different categories of performance tests, SLAs backed by real assertions, actually reading the report, a working CI pipeline with proper environment handling, and finally scaling beyond a single machine along with the habits that keep it all healthy.
None of this needs to land in a single sprint on a real project. Build it up in roughly this order, the same way we walked through it here, and each piece supports the ones that come after it.