LOADLINEsystem-design simulation · requirements → architecture → simulation → failure → diagnosis

How LOADLINE simulates an architecture

LOADLINE is a deterministic, discrete-event simulation (DES) of your architecture. Simulated time is an integer nanosecond counter fully decoupled from wall-clock time: a 60-second horizon runs in milliseconds. Requests arrive, queue, consume service time and complete — every metric the UI shows is measured from those events, never fabricated to look realistic.

What LOADLINE is: an explainable, reproducible simulation with explicit assumptions. What it is not: a production-accuracy oracle — modeled ceilings and cost figures are estimates from labeled local models, not guarantees or live billing.

From users to peak RPS — the workload chain

User-level requirements are converted through an explicit chain with every intermediate value exposed in the run plan. Nothing jumps from “1M users” to “10k RPS” without showing its work:

RequestsPerDay = DAU × RequestsPerUserPerDay
AverageRPS    = RequestsPerDay ÷ 86400
PeakRPS       = AverageRPS × PeakMultiplier
ReadFraction  = ReadWriteRatio ÷ (ReadWriteRatio + 1)
MeanInterArrivalMillis = 1000 ÷ PeakRPS

Arrivals are a homogeneous Poisson process: exponential gaps drawn from a seeded stream, with mean rate exactly PeakRPS at peak. Values are validated before the run starts (DAU ≤ TotalUsers, PeakMultiplier ≥ 1, non-negative payload), and invalid specs are rejected explicitly rather than silently accepted.

Component models

Nine generic component kinds carry the behavior; provider services (Cloudflare, AWS, GCP) map onto them in the catalog layer, so the engine itself never contains provider-specific branches.

KindModeled behavior
clientGenerates Poisson arrivals at the configured peak RPS and receives responses.
load balancerRoutes with its own concurrency and queue; optional fan-out replicates a request to N downstream targets.
api serverComputes service time per operation and forwards reads and writes along its links.
cacheReads hit with the configured probability (seeded roll) and terminate; misses and writes continue downstream.
queueZero-delay pass-through that buffers into exactly one linked worker — the worker's queue holds the real backlog.
workerAsync compute: drains its queue with its concurrency slots; terminal node.
databasePriced read/write service times — the classic bottleneck.
object storagePriced get/put service times.
networkPure transit-latency hop, unconstrained.

Architectures are validated before any run: exactly one client, no cycles, every node reachable, every queue fed by exactly one worker.

Queueing and latency

Queues are real system state — one FIFO line per constrained component. When arrival rate exceeds service rate, depth grows; the trend classifier reports growing, draining orstable. Admission rejects only when concurrency slots are full and the queue is at its limit; rejected requests never enter service, so they are excluded from latency percentiles and tracked as a rate instead.

request latency = Σ over visited components (
    queue wait    — time in that component's FIFO
  + service time  — spec service time + injected failure penalty
)
+ transit         — unconstrained hops (network, client)

Tail latency emerges from queueing: under load, p99 grows because later requests wait behind earlier ones. Percentiles are nearest-rank over actual per-request observations (rank ceil(p × n) of sorted latencies) — there is no artificial tail multiplier anywhere in the engine.

Failure injection and cascades

TypeEffect while active
crashThe component cannot serve: requests fail at it (or pass through untouched when configured, e.g. cache → origin).
increased latencyA fixed per-request service-time penalty while active.
increased error rateA fraction of serviced requests fails while active.
network failureTransit latency inflation plus packet loss (drops).

Failures modify simulation state — they are not a red icon. Cascades are emergent, never scripted: a crashed cache produces misses, cache misses become database traffic, database arrival exceeds its capacity, the queue grows, percentiles rise, callers with budgets time out, and retries re-enter the failing component and amplify the load. A test asserts each link of that chain from measured numbers.

Metrics and their definitions

MetricDefinitionScope
ThroughputCompleted requests ÷ measured windowper component, window average
Error rateFailed ÷ generated requestssystem, cumulative
p50 / p95 / p99Nearest-rank percentile over per-request terminal latenciessystem, per request
Queue depthCurrent FIFO length; max depth is the high-water markper component, instantaneous / max
UtilizationBusy time ÷ (concurrency × window)per component, window average
Arrival vs capacity RPSArrived ÷ window against the configured modeled ceilingper component, window average
Headroom1 − utilization (and 1 − arrival/capacity)per component

The run satisfies a conservation invariant — generated = completed + rejected + failed + in-flight — asserted by tests including fan-out and horizon-edge cases.

Capacity model

For each provider-backed component the modeled ceiling is derived, not guessed, and the derivation is printed in the report's assumption trail:

MaxSustainableRPS = concurrency ÷ effective service time   (static kinds)
                  = catalog ModeledRPS                            (serverless kinds)
Headroom          = 1 − Utilization
Saturated         = arrival exceeded the modeled ceiling
Example: 8 database slots ÷ 5 ms service ≈ 1,600 RPS modeled ceiling — “arrival is 50% of ceiling” is then a measured statement about the run, not a marketing number.

This is a modeled ceiling of the current configuration — an estimate from the service model, not a measured quantity and not a guaranteed production limit. Real systems usually degrade earlier (contention, GC, hot keys, connection pools).

Cost estimation

Cost consumes simulation outputs — it never lives inside component logic:

simulation outputs (completed requests, GB-s busy, window)
   ↓ scale to a 730h month at observed average rates (factor printed)
pricing model per service (unit prices + free-tier allowances)
   ↓
monthly estimate with full assumption trail

Every line item carries component, category, quantity, unit, unit price and monthly cost; every estimate carries the scale factor, the workload basis (DAU × requests/user/day) and the marker that prices are local mid-tier-region estimates. Pricing models cover per request, compute time, instance-hour, storage/month and bandwidth/egress. It is always labeled an estimate — never live billing.

Determinism and reproducibility

Given identical architecture, workload, failures, duration and seed, runs are byte-identical. Randomness is SplitMix64: each event draws from an independent stream derived from (runSeed, eventID), events are ordered by (timestamp, ID) with monotonically increasing IDs, no wall clock enters any scheduling path, and unseeded runs default to seed 1. Tests lock this at the engine, sim, API and pacing layers.

Known limitations

Honesty is part of the model — the engine deliberately does not model:

Open the simulatorRead the FAQFull model spec (markdown)Source on GitHub