Load test · experiment assignment engine · 2026-07-30

Experiment assignment at sub-5ms, 10K requests a second. Battle-tested.

We don't say fast — we show you the run. Every performance number on this stack is measured, not marketed. Here's the k6 load test that produced this one, with the full method and the raw output.

Sustained rate
10K req/s
~5 min plateau
Assignment p95
1.31ms
p99  3.71 ms
Errors
0.00%
0 / 3,846,561
Median
0.50ms
avg  0.69 ms
01 · The result

Every threshold, passed

The k6 summary from the run — assignment latency, check rate, and failure rate, straight off the terminal. No post-processing.

k6 run — summary
k6 terminal summary: assignment latency p95 1.31ms, p99 3.71ms, 100% of 7,693,122 checks succeeded, 0% of 3,846,561 requests failed.
p95 1.31 ms · p99 3.71 ms · 7,693,122 checks, 0 failures
02 · The run, live

Rate climbs to 10K and holds

The k6 dashboard in real time. Request rate ramps to 10,000/s and stays there; the latency line stays flat along the floor the entire time.

k6 dashboard — localhost:5665
2.25× speed · green = request rate, blue = p95 latency, purple = failures (flat at zero)
03 · The distribution

The whole latency spread

Not one cherry-picked number — the full percentile distribution, measured end-to-end and server-side.

Metricp50p90p95p99avg
Assignment latency end-to-end 0.500.881.313.710.69
Server processing excl. network 0.470.821.220.65
All values in milliseconds · 3,846,561 assignments · 0 errors · thresholds p95<5ms and p99<15ms both passed with wide margin
+

And this is the engine on its worst day.

This test ran 100% cold — every request was a brand-new user, forcing a full experiment assignment (segment match, deterministic bucketing, and exposure write) on the spot. That's the most expensive path the engine has.

In production it isn't the common one. Returning users are served from cache at near-zero latency, and real traffic is typically 60–80% returning — so the latency your users actually see sits well below the numbers on this page. We published the hard case on purpose.

04 · The method

What the test actually was

The setup matters more than the number. Here's exactly what produced it.

Endpoint under loadPOST /v1/experiments/assign — the full experiment-assignment path: segment match, deterministic bucketing, and exposure write, all on the request.
Assignment path100% cold, new-entity — every request a first-time user drawn from a 1,000,000 pool. No pre-warmed cache doing the easy work.
ServerSingle AWS c6i.xlarge (4 vCPU) running the API, worker, Postgres, and a two-instance Redis topology under Docker Compose.
Load generatorSeparate c6i instance running k6, ramping arrival rate 500 → 10,000 req/s over the private network.
Volume3,846,561 assignments served in the measured window; 7.69M checks, all passed.
Evaluation modelIn-process, in-memory config cache — assignment resolves with zero network calls off the request path.

One honest note on the number: 10K is the sustained plateau, measured across the five-minute hold. The whole-window average is lower (~8K/s) because it folds in the ramp-up and cool-down — arithmetic, not a ceiling. At 1.3 ms p95 on a single 4-vCPU box, the server had headroom to spare; the number scales with the hardware behind it.