Load Profiles¶
Scale Sentry's loadgen runs an ordered list of phases. Each phase carries its own arrival pattern, rate, and duration. The default (single-phase, constant-rate) is what older ScaleValidation CRs land on, but spec.load.profile unlocks open-loop and multi-phase shapes that exercise the autoscaler more realistically.
Why open-loop matters¶
Closed-loop benchmarks (one request, wait for response, send the next) hide the moments when the target stalls: a 200ms backend pause just means each worker sends fewer requests, and the latency histogram still looks healthy. Open-loop generators emit requests on a schedule regardless of how fast the target replies, so a stall shows up as growing queue depth and elevated tail latency. That is the failure mode an HPA needs to react to.
The scale-sentry loadgen also applies the scheduled-arrival fix for coordinated omission: every request's latency is measured from the slot's scheduled time, not from the moment the worker actually dispatched it. A stalled target turns into honest p99 growth instead of silently-absorbed queue wait.
Patterns¶
spec.load.profile.pattern selects the arrival shape. Pattern-specific knobs apply only to their named pattern; the rest are ignored.
| Pattern | Shape | Use when |
|---|---|---|
Constant |
Fixed rate (legacy default) | Smoke testing; comparing against pre-loadprofile baselines |
Poisson |
Exponential inter-arrival, mean 1 / baseRps |
SLA-accurate verdicts; matches real user traffic |
Ramp |
Linear interpolation baseRps → endRps over rampDuration |
Measuring HPA reaction latency under monotonic growth |
Step |
Climbs stepRps every stepDuration, holding each plateau |
Stressing HPA stabilization windows and downscaling hysteresis |
Spike |
Decomposed into Constant base / spike / base / ... by the controller | Reproducing diurnal traffic spikes and noisy-neighbour patterns |
Warmup phase¶
spec.load.warmupDuration runs traffic against the target before the SLA window opens. Requests are dispatched (so TCP/TLS handshakes settle, JIT runs, page caches warm) but their latencies and counters are excluded from the verdict. The warmup phase always runs at baseRps with the Constant pattern.
spec:
load:
baseRps: 200
warmupDuration: 30s # 30s warmup then the measurement window
profile:
pattern: Poisson
Skip the warmup (omit warmupDuration) when comparing against the older single-shot defaults; otherwise enable it for any verdict that needs to survive code review.
Spike profile¶
The Spike pattern stitches one or more elevated-rate windows into a baseRps Constant background. The controller decomposes the spike into atomic phases before sending them to the loadgen, so the SLA verdict reflects each slice individually.
spec:
load:
baseRps: 100
profile:
pattern: Spike
spikes:
- at: 30s # offset from measurement start
duration: 10s
rps: 600
- at: 90s
duration: 5s
rps: 1200
at is measured from the start of the measurement phase (post-warmup). Spike RPS must exceed baseRps; otherwise it would be a dip, which is rejected by the CRD.
Phase summaries in the result¶
Every executed phase contributes a PhaseSummary to the run output:
{
"phases": [
{ "name": "warmup", "pattern": "Constant", "recordStats": false, "started": "...", "ended": "..." },
{ "name": "measure", "pattern": "Poisson", "recordStats": true, "started": "...", "ended": "..." }
],
"warmupDuration": "30s",
"measurementDuration": "3m0s"
}
WarmupDuration and MeasurementDuration sum the wall-clock spent in each kind of phase. Use them to confirm a long run actually entered the measurement window before drawing verdicts.