Virtual users and concurrency
Three terms appear constantly in load-testing configuration and results: virtual users, concurrency, and requests per second. They are related but distinct. Confusing them leads to tests that don’t represent real traffic and results that are hard to interpret.
Virtual users (VUs)
Section titled “Virtual users (VUs)”A virtual user (VU) is a simulated entity that runs your test script from start to finish, repeatedly. Each VU:
- Executes a request (or a sequence of requests defined in the scenario).
- Optionally waits (think time / pacing).
- Loops back to step 1.
In MaxoPerf, the VU count you configure is the number of VUs running simultaneously across all allocated runners. If you configure 100 VUs and two runners, MaxoPerf distributes 50 VUs per runner.
VUs are a closed workload model: the number of concurrent users is fixed. The system under test controls how fast they progress by controlling response time. See Open vs closed workload models for when a fixed VU count is — or isn’t — the right model.
Concurrency
Section titled “Concurrency”Concurrency is the number of requests that are in flight simultaneously at a given instant — requests that have been sent but not yet received a complete response.
Concurrency is not the same as VU count. A VU that is waiting during think time is not contributing to concurrency. A VU that is slow to receive a response (because the system is slow) holds a concurrent slot longer.
The relationship is:
concurrency ≈ VU count × (request time / (request time + think time))With no think time (think-time: 0s in Taurus), concurrency approaches the VU count — every VU
is always waiting for a response. With 5 seconds of think time and 200 ms request time, concurrency
is much lower than VU count (most VUs are idle in think time, not in flight).
Requests per second (RPS)
Section titled “Requests per second (RPS)”Requests per second (RPS) — also called throughput — is the rate at which requests complete. It is the output of the system, measured by the MaxoPerf runners.
The theoretical maximum RPS for a given VU count and zero think time is:
max RPS = VU count / p50 latency (in seconds)Example: 100 VUs, p50 latency 200 ms → max ~500 RPS. If actual RPS is lower, requests are queued or the system is slower than expected.
The glossary definitions
Section titled “The glossary definitions”The virtual users glossary entry has the formal definition and a quick-reference comparison table. This page gives the practical load-testing context.
How MaxoPerf exposes VU count
Section titled “How MaxoPerf exposes VU count”The run-detail Summary header shows the VU count the test was configured with. The Runners tab shows how VUs are distributed across runners during and after the run. The Overview tab throughput chart shows the RPS the system actually achieved.
Mapping VUs to real users
Section titled “Mapping VUs to real users”A common question: “How many VUs simulate 10 000 daily active users?”
There is no direct mapping without knowing the user session pattern. A rough estimate:
concurrent VUs ≈ (daily active users × avg session duration in seconds) / 86 400Example: 10 000 DAU × 5-minute session (300 s) / 86 400 s = ~35 concurrent users at average load. For peak load (often 3–5× average), plan for 100–175 concurrent VUs.
See How much load do you need? for a detailed sizing walk-through with real numbers.
VUs in Taurus YAML
Section titled “VUs in Taurus YAML”In a Taurus YAML script, VU count is set with the concurrency key in the execution block:
execution: - concurrency: 100 hold-for: 10m ramp-up: 2m scenario: my-scenarioThis tells MaxoPerf to ramp from 0 to 100 VUs over 2 minutes and hold for 10 minutes. During the hold phase, 100 VUs are continuously executing the scenario in a closed loop.
VUs in k6
Section titled “VUs in k6”In k6, VUs are configured with the vus option:
export const options = { vus: 100, duration: '10m',};k6 also supports the stages array for ramp patterns — see the
k6 scripts on Maxoperf page.
Do / don’t
Section titled “Do / don’t”| Do | Don’t |
|---|---|
| Distinguish between the VU count (what you configured) and RPS (what the system delivered). | Treat VU count as a proxy for RPS — they are only equal at 1 req/VU/s with no think time. |
| Add realistic think time to simulate how real users pause between actions. | Use 0 think time for every test — it maximizes pressure but rarely matches real traffic patterns. |
| Check the Runners tab to confirm VUs were distributed as expected across locations. | Assume all VUs ran on a single location when you configured multi-region. |
| Use the VU sizing formula when translating traffic analytics to a load profile. | Pick VU counts arbitrarily or by copying a colleague’s config without understanding the traffic pattern. |
Where to go next
Section titled “Where to go next”- Virtual users — formal definition and quick-reference table.
- Open vs closed workload models — when a fixed VU count (closed) versus an arrival rate (open) is the right model.
- Ramp-up, think time, and pacing — shaping the load profile around VU count.
- How much load do you need? — sizing a test from real traffic data.