constantConcurrentUsers + throttle vs constantUsersPerSec for bounded Gatling heap at target RPS
0 reputation · 02 Jul 2020, 09:42 UTC
0 reputation · 02 Jul 2020, 09:42 UTC
The goal is to hold a target request rate while keeping the Gatling load generator's own heap bounded, but the two documented injection strategies pull in opposite directions. A closed-workload profile such as constantConcurrentUsers(n).during(d) combined with throttle(...reachRps(r)...) keeps N sessions resident for the entire run, so memory scales with concurrency times session and feeder size. An open-workload profile such as constantUsersPerSec(r).during(d) keeps only short-lived users, so resident sessions track response time times arrival rate.
The unresolved behavior is that throttle acts only as a cap, never as a generator: if the injection profile cannot supply enough concurrent users, or the system under test is too slow, the reachRps target is silently missed without raising an error. With the closed profile, slower responses make users queue inside Gatling instead of shedding load, which can grow heap through pending requests and retained sessions. With the open profile, arrivals decouple from response time, but overshoot can overload the target.
Which profile better bounds load-generator memory when system-under-test latency is variable? Can throttle steps be configured to fail or warn when a reachRps step is not actually reached? Does the feeder replay strategy materially change the resident-memory trade-off between the two profiles?
35275 reputation · 02 Jul 2020, 18:57 UTC
For a variable‑latency system under test, the open‑workload profile constantUsersPerSec(r).during(d) bounds the Gatling load‑generator heap better than the closed‑workload profile constantConcurrentUsers(n).during(d) combined with throttle(...reachRps(r)...).
With constantConcurrentUsers the same N virtual users stay resident for the whole simulation. If the SUT slows, those users block inside Gatling, retaining their session objects, stacks and any pending request state, so heap can grow with queueing depth. throttle only caps the offered request rate; it does not create users and does not verify that the cap is actually met, so a missed reachRps target is silent.
With constantUsersPerSec new users are injected at a fixed rate regardless of response time. The resident population approximates r × mean latency (Little’s law), which stays bounded even when latency spikes, because finished users are discarded and their memory reclaimed. The trade‑off is that arrivals do not back‑off, so a slowing SUT can be overloaded, but the load‑generator’s own heap remains smaller.
throttle steps (reachRps, jumpToRps, holdFor) are rate limiters only; they do not generate users and do not raise an error when the target rate is not achieved.reachRps step; you must add an external check (e.g., parse the simulation log or use a custom assertion) to detect the gap.queue, circular, random, shuffle) affect how feeder records are reused or exhausted, but they do not change the fundamental memory relationship between the two injection profiles; the feeder’s resident cost is added equally to both profiles.jstat, or container metrics.reachRps value with the actual requests/sec from the Gatling report; a discrepancy confirms throttle acted only as a cap.Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.