Q5 of 38 · Performance

What's the difference between concurrency and arrival rate?

PerformanceJuniorperformanceload-modelsconcurrencyarrival-ratek6

Short answer

Short answer: Concurrency (closed model) holds N users active at once — if the system slows, fewer requests per second. Arrival rate (open model) injects R requests per second regardless of latency — if the system slows, queue grows. Real production traffic behaves like an open model.

Detail

Closed-model (concurrency-based) load: you specify N virtual users, each loops "send request, wait for response, sleep, repeat." If response time doubles, the same N users send half as many requests per second. Throughput is bounded by the system's speed. This is what JMeter Thread Groups and k6 vus do by default.

Open-model (arrival-rate-based) load: you specify R requests per second injected into the system, regardless of how long each takes. If response time doubles, requests pile up — queue depth grows, latency tail explodes, errors arrive. This is what k6 constant-arrival-rate or Gatling constantUsersPerSec do.

Why it matters: production traffic is open. Real users don't politely wait for one slow response before sending the next click — they refresh, retry, and new users keep arriving. A closed-model test on a struggling system masks the failure: throughput drops, but error rate stays low because no requests are queueing. An open-model test reveals what production actually feels: queue saturation, timeouts, cascading failure.

Use closed-model when you want to verify behaviour under steady-state load. Use open-model when you want to know how the system fails under traffic spikes — which is what stress and spike testing actually want to measure.

// EXAMPLE

k6-open-vs-closed.js

// Closed model — 50 VUs sending continuously
export const options = {
  scenarios: {
    closed: {
      executor: 'constant-vus',
      vus: 50,
      duration: '5m',
    },
    // Open model — 100 RPS injected regardless of latency
    open: {
      executor: 'constant-arrival-rate',
      rate: 100,
      timeUnit: '1s',
      duration: '5m',
      preAllocatedVUs: 50,
      maxVUs: 500, // grows when system slows
    },
  },
};

// WHAT INTERVIEWERS LOOK FOR

Understanding that closed-model is bounded by system speed while open-model isn't, and that production behaves like open. Bonus: knowing which executor mode in their tool gives each.

// COMMON PITFALL

Running only closed-model tests and concluding the system 'handles 50 users fine' — the test slowed down with the system and never created the queue conditions production will see.