Performance Testing
Intermediate 12 min read Performance Testing

Load Models & Scenarios

A load model describes how traffic arrives over time: ramping, steady state and spikes, expressed either as concurrent virtual users or as arrivals per second. Choosing the wrong model is the most common reason load tests misrepresent production.

load modelexecutorramping-vusarrival ratestagesthink time
Prerequisites: Metrics & Baselines
Introduction

What is this?

A load model describes how traffic reaches a system over time: how many users, how quickly they arrive and for how long. It is expressed as executors and stages — ramping up, holding steady, ramping down — or as arrival rates (requests per second) when throughput is the question. Choosing the wrong model is the most common reason load tests misrepresent production.

Motivation

Why do you need it?

  • Production traffic is not steady — it ramps, spikes and follows daily patterns, so a flat model cannot validate capacity.
  • Arrival-rate models test throughput limits directly, while VU-based models test concurrency limits — they answer different questions.
  • Realistic think time and pacing make the requests per second you generate match what real users actually produce.
  • Repeatable models let teams compare runs across versions with a known, versioned workload.
  • Modeling peak (e.g. Black Friday) and off-peak separately reveals whether autoscaling reacts fast enough.
Think about it

Mental model

Imagine

A busy coffee shop

Think of

A load model

The manager cares about both how many customers are in line (concurrent users) and how many drinks are made per hour (throughput). Opening an espresso bar changes the arrival model; adding a second barista changes capacity. Load models capture that same distinction.

Mechanics

How it works

  • Pick the model axis: concurrent VUs (users in the system) or arrival rate (requests arriving per second).
  • Define phases as stages: ramp-up, steady state and ramp-down, each with a target value.
  • Set think time so each VU's request rate matches a realistic user, and pacing for arrival models.
  • Run the model against the target and measure whether the system holds SLOs at each phase.
  • Store the model with the script so later runs and capacity reviews use the identical workload.

Common load model shapes and the load they create over time.

Load model
Ramp-up
Steady state
Spike
Ramp-down
Compare to SLOs
Reference

Key commands

k6 run --scenario vu-based script.js

Run only the VU-based scenario from a multi-scenario script.

k6 run --scenario arrival-based script.js

Run only the arrival-rate scenario to probe raw throughput.

k6 run --vus 0 --stage 1m:100 --duration 3m script.js

CLI shorthand for a one-minute ramp to 100 VUs without editing the script.

k6 inspect script.js

Print the effective options, including resolved scenarios and executors.

exports: {default: {...}}, options: {scenarios: {...}}
k6 run --max-duration 10m script.js

Hard cap on run length even if an executor misconfigures its duration.

k6 run --summary-export summary.json script.js

Export a machine-readable summary for comparing models across runs.

Hands-on

Examples

Arrival-rate and VU-based scenarios in k6

Arrival-rate and VU-based scenarios in k6
import http from "k6/http"
import { sleep } from "k6"
export const options = {
scenarios: {
"vu-based": {
executor: "ramping-vus",
startVUs: 0,
stages: [
{ duration: "1m", target: 200 },
{ duration: "5m", target: 200 },
{ duration: "1m", target: 0 },
],
gracefulRampDown: "30s",
},
"arrival-based": {
executor: "constant-arrival-rate",
rate: 100,
timeUnit: "1s",
duration: "5m",
preAllocatedVUs: 50,
maxVUs: 200,
},
},
}
export default function () {
http.get("https://api.example.com/v1/items")
sleep(0.5)
}

The first scenario keeps 200 concurrent users in the system with a five-minute steady state; the second sustains 100 requests per second regardless of how fast responses return. Running both answers two different questions: can we serve 200 simultaneous users, and can we sustain 100 RPS?

Real world

In production

  • Peak-day models (e.g. Black Friday ramps) run in staging weeks before an event to validate autoscaling.
  • Arrival-rate models set throughput budgets for API gateways and are reused in charge-back capacity planning.
  • Modeled workloads feed soak tests so the request mix matches production read/write ratios.
  • Versioned load models are the contract between the performance team and the platform team for shared capacity.
Guidelines

Best practices

  • Match the model to the question: VUs for concurrency limits, arrival rate for throughput limits.
  • Include realistic think time and a representative request mix rather than one hot endpoint.
  • Record the model in the script so everyone can read the intended shape.
  • Ramp slowly enough to observe degradation points instead of blasting straight to the peak.
  • Re-run the same model after infrastructure changes to attribute changes to the app or the platform.
Watch out

Common mistakes

  • Using a steady flat load for everything, missing the spikes and soak phases production really has.
  • Confusing VUs with RPS — 200 VUs with 1s think time is about 200 RPS, but without think time it is many times more.
  • Ramping too fast to observe where the system starts to degrade.
  • Forgetting gracefulRampDown, so VUs are cut mid-request and the final stage pollutes the summary.
Root cause analysis

Common issues

Error
insufficient VUs, reached the maximum number of VUs
Root cause

An arrival-rate scenario ran out of preallocated VUs to keep up with the target rate.

Fix

Raise preAllocatedVUs and maxVUs in the scenario options.

Error
the threshold 'http_req_duration' failed 50.00% of the time
Root cause

Load exceeded capacity partway through the model, typically during the spike stage.

Fix

Split results by stage with tags or identify the ramp point where latency crossed the budget.

Error
script.js: executor 'ramping-vus' does not accept 'rate'
Root cause

Options from one executor were pasted into another.

Fix

Use each executor's documented options: stages for ramping-vus; rate and timeUnit for arrival executors.

When things break

Debugging tips

  • Plot vus and http_reqs over time — a flat vus line with climbing latency means saturation, not a traffic problem.
  • Compare RPS achieved vs target in arrival models; a shortfall means the system can't keep up, not a script bug.
  • Use --summary-export to see exactly when thresholds started failing per stage.
  • Look at iteration rate rather than raw counts when think time changes between runs.
Interviews

Interview checkpoint

Practice

Hands-on lab

Model Production Traffic from an Access Log
35 min · intermediate
In progress
Objectives
  • Generate a synthetic hourly request pattern from an access log
  • Translate the pattern into a ramping load model
  • Run the VU-based model and read the peak concurrency
  • Add an arrival-rate scenario and compare the two perspectives

Model Production Traffic from an Access Log

35 min · intermediate

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which executor is best when the goal is to sustain exactly 500 requests per second?

2

In k6, 100 VUs always generate exactly 100 requests per second.

3

A system degrades only when traffic jumps quickly. Which stage shape best exposes this weakness?

Quick reference

Cheat sheet

Load model shapes
ramping-vusRamp users over stages
constant-vusFixed concurrent users
constant-arrival-rateFixed RPS — throughput test
ramping-arrival-rateScale RPS over stages
stages: [1m:100, 5m:100, 1m:0]Ramp, hold, ramp-down
gracefulRampDownLet in-flight requests finish
Go deeper

Official documentation