# k6 Harness: Fraction-Cent Costs, Sizing, Tickets, Soak Bounds

Kenji Sato · August 25, 2026

> k6 Harness: Fraction-Cent Costs, Sizing, Tickets, Soak Bounds. A two-second average session can conceal an eight-to-fifteen-second ta...

| Takeaway | Detail |
| --- | --- |
| Size the bot fleet by memory, not CPU. | Chrome typically needs 1-2 GB of RAM per rendered client, so a soak harness provisioned by core count hits host memory limits first and forces overprovisioning during peak windows. |
| Medians hide the tail that decides p95 queue time. | prerender.info documented a 2-second average session render concealing an 8-15 second long tail, and warns that load models built on one happy-path median routinely underestimate production load. |
| Fraction-cent compute is real but seductively incomplete. | The naive spreadsheet path — model 100,000 sessions at 2 seconds each, multiply by cloud CPU pricing, conclude DIY costs almost nothing — fails because visible Chrome compute is usually the smallest number in the spreadsheet. |
| Budget tickets and people alongside machines. | Operating an automated-client pool takes 0.2-0.5 FTE of platform time, and the first month typically introduces browser crashes, stale-output incidents, queue backlogs, traffic bursts, and on-call work absent from the original estimate. |

A two-second average session can conceal an eight-to-fifteen-second tail, and prerender.info's load-modeling work shows that plans built on the happy-path median systematically underestimate peak demand. Matchmaking behaves the same way. Split 500 concurrent players across 3 regions and 3 party sizes and you are not running one queue — you are running up to nine, and the p95 wait you actually care about lives entirely in the fragmented tails.

That is why ten human playtesters are instrumentation, not evidence. Their queue times carry no statistical weight at 500 CCU; they sample the median and never reach the tail. A scripted bot soak, by contrast, can hold every partition populated through an afternoon, surfacing the backlog dynamics, retry behavior, and timeout thresholds that only a sustained synthetic population exposes.

The catch is sizing and tickets. Each automated client can claim 1-2 GB of RAM before CPU ever becomes the binding constraint, and the visible compute is the smallest number in the spreadsheet: plan on 0.2-0.5 FTE of platform time, plus first-month surprises like crashes, stale output, and queue backlogs that no original estimate included.

![k6 Harness](https://static.mm-ais.com/article-images-ai/k6-harness-fraction-cent-costs-sizing-ti-ai-2fbd225c.jpg)

## Inside the Harness

Queue time is a batching problem, not a server-capacity problem. Expected wait ≈ lobby_size ÷ (arrival_rate × fill_efficiency): a 16-slot lobby fed by 32 arrivals per minute fills in roughly 30 seconds at perfect efficiency, and faster still when the matcher batches partial lobbies. Server hardware never enters the equation until after the match is formed — which is why adding boxes does nothing for a slow queue, and why the gate reads p95 queue time rather than CPU headroom.

| Tier | What it exercises | Cost per seat-hour | Role in the gate |
| --- | --- | --- | --- |
| Protocol-level bot | Matchmaking/session API directly — e.g., PlayFab Matchmaking tickets over REST | Fractions of a cent | Wins the gate: supplies nearly all of the bot mass at 500 CCU |
| Headless engine client | Real engine netcode via containerized Unreal/Unity server builds, no rendering | Usage-based, priced per replica | Supporting slice: validates post-allocation session traffic |
| Humans-on-hardware | Full client with real perception — desync, hit registration, voice chat | Bounded by headcount, not compute | Fidelity instrumentation only — never load generators |

The go/no-go dashboard therefore reads three server-side contracts, and the harness must scrape all three every poll cycle. According to Microsoft's PlayFab Matchmaking documentation, the QueueStatistics endpoint exposes tickets queued and average seconds-to-match. According to the Open Match project's documentation, the Director generates matches on a default 10-second tick. Agones emits GameServer allocation events as servers are claimed. Client-side timers alone miss server-side batching delay — a bot starting its stopwatch at ticket creation cannot see the Director sitting idle between ticks.

Every bot must execute the complete ticket lifecycle: create ticket → receive match → ACCEPT → join the allocated server → heartbeat for the session length → clean disconnect. The accept step is where naive harnesses cheat. Skip it and abandoned tickets leak back into the pool, deferring queue pressure to later in the run — a soak that holds early and collapses late is usually leaked tickets masquerading as instability, not dying hardware.

Ramp in steps: 10 humans plus bots starting at 50 CCU and stepping up through intermediate plateaus to 500 CCU, holding each plateau for 10 minutes. Matchmaking warm-up caches and allocation pipelines need roughly two plateau cycles to reach steady state; a straight jump to 500 measures cold-start behavior and nothing else. If the gate run begins at full load, you validated your bootstrap path, not the queue players will join.

Position the 10 humans correctly and the myth dies on contact. They occupy a single lobby to validate what bots cannot — desync, hit registration, voice chat — while bots saturate the remaining ~30 lobbies. Humans are fidelity instrumentation, not load generators, and their personal queue times are anecdote, not data. A producer who watched ten colleagues match in fifteen comfortable seconds watched one lobby out of thirty, timed client-side, blind to the server-side batching the other twenty-nine ran under. Before signing the go, confirm the scraped QueueStatistics samples — not anyone's stopwatch — carried the p95 bar across the gate's full 30-minute hold at 500 CCU.

According to Grafana's k6 documentation on load-generator sizing, a single adequately provisioned instance sustains far more protocol-level virtual users than a matrix of this size demands. Your full 500-CCU matrix fits inside one box several times over, with headroom left for stepped ramps. The scarce resource in 2026 is not compute — it is harness engineering: bots that faithfully complete the full ticket lifecycle instead of opening sockets and idling.

![Inside the Harness — k6 Harness](https://static.mm-ais.com/article-images-ai/k6-harness-fraction-cent-costs-sizing-ti-ai-5ebcb0f8.jpg)

## Proven Envelope

The server side is even more lopsided. According to the Agones project's own scaling write-ups, a single Kubernetes cluster manages GameServers at a scale far beyond anything a soak demands. A 500-CCU soak consumes roughly 32 dedicated servers — comfortably inside the proven envelope. The operational consequence is blunt: when a run collapses, "the infrastructure couldn't take it" is never an acceptable root cause. The failure lives in your ticket-lifecycle code, your scenario weights, or your acceptance-rate assumptions, and naming it correctly is what makes the next run pass.

Benchmarks need anchors, and vendors publish them. According to Microsoft's PlayFab Matchmaking documentation, the service exposes per-queue statistics alongside reference guidance targeting matches in roughly 30 seconds or less for casual pools. That hands a studio a vendor-stated baseline to judge its 500-CCU p95 against — if your result sits far above a figure the vendor publishes for casual traffic, you owe reviewers a named reason (party-size mix, regional thinness) rather than a shrug.

But the anchor is a policy dial, not physics. According to Riot Games' public GDC matchmaking talks, Riot deliberately trades queue time for match quality, holding skill-band width near-fixed and accepting longer waits for tail-population players. This is where the ten-human playtest myth dies: "we matched in under 15 seconds" describes a pool that regions, platforms, and party sizes have not yet sliced thin — and queue time scales superlinearly as those slices multiply, so the same design routinely stretches past 90 seconds at 500 CCU. Fix the per-genre target before the soak runs, or the run produces a number with no verdict attached to it.

Finally, the gate is now staffable. According to Epic Online Services documentation, matchmaking ships free with documented regional pool separation, and queue telemetry has become standard tooling across major platform vendors. A five-person live-ops team can operate a 500-CCU gate that, only a few years back, demanded a dedicated backend squad.

Concrete next step: pin the k6 sizing page, the Agones scaling notes, and the PlayFab queue statistics to your gate-review run sheet, and adopt one standing rule — any "infrastructure limits" claim must cite a graph that actually crosses one of these published ceilings. In practice, nobody ever produces one.

| Envelope component | Proven ceiling (source) | 500-CCU demand | Verdict |
| --- | --- | --- | --- |
| Load generation | Virtual-user capacity far above matrix demand (Grafana k6 docs) | Covers the whole matrix several times over | Compute never the constraint |
| Game server capacity | GameServer capacity per cluster far beyond soak demand (Agones scaling write-ups) | Roughly 32 dedicated servers | Ample headroom |
| Queue-time anchor | ~30 seconds for casual pools (PlayFab Matchmaking docs) | Judge p95 against the article's 60-second gate | Baseline exists; deviations need named causes |
| Target calibration | Skill band held near-fixed, waits traded (Riot GDC talks) | Per-genre target set pre-run | Policy choice, not physics |
| Telemetry and tooling | Free matchmaking with regional pools (Epic Online Services) | Standard platform-vendor stack | Small-team gate is viable |

The stack decision collapses to one question: how many tickets does a single run generate? A 500-person crowdtest yields exactly 500 queue events — one sample of the distribution you're gating on, with no variance estimate. Protocol bots generate thousands. And retire the oldest line in playtest retrospectives: "our ten humans matched in under 15 seconds, so we're fine." Queue time scales superlinearly with pool fragmentation — regions, platforms, and party sizes carve the pool into thin slices — so a 15-second wait at 10 players routinely becomes 90-plus seconds at 500 CCU. Ten humans sit at the flat origin of that curve and cannot see the bend.

![Proven Envelope — k6 Harness](https://static.mm-ais.com/article-images-pixabay/k6-harness-fraction-cent-costs-sizing-ti-30a2f3a3.jpg)

## Choosing the Stack

Why the spread? According to Scrapfly's headless-browser guidance, every launched client instance consumes host CPU, RAM, and disk on the machine running it, so engine clients price per replica while protocol bots price per connection. According to prerender.info's fleet-cost analysis, the expensive part is never the client — it's the system around it: concurrency control, queueing, retries, monitoring, and the people who keep it healthy when volume spikes. Build-versus-buy goes wrong when teams model raw compute and ignore that operating layer. Scored on the two axes that matter for a queue gate — statistical power and behavioral fidelity — the explicit winner is the hybrid: protocol bots carrying roughly 98% of load, ten humans riding along so accept behavior stays real. A composite-risk-score pattern described on Medium earlier this year, built for fraud detection, transfers directly to separating human sessions from bot sessions in that mixed run.

| Candidate stack | Compute per 500-CCU run | Setup | Tickets per run | Fidelity |
| --- | --- | --- | --- | --- |
| Protocol-bot harness (k6 or bespoke API client) | Minimal usage-based compute | ~1 engineer-week | Thousands | Approximate — speaks the ticket lifecycle, not the game |
| Containerized headless engine clients | Meaningful per-replica compute spend | Plus 2–3 weeks of image engineering | Bound by host fleet — every instance consumes host CPU, RAM, and disk | Highest synthetic fidelity |
| Outsourced human crowdtesting | Dominated by headcount cost, not compute | Weeks of scheduling lead time | Exactly 500 | Real humans, but n far too small to gate on |

Those runs feed a three-band gate:

Toolchain follows estate, not preference. Studios already on Azure/Kubernetes get PlayFab Matchmaking + Agones + k6 as the default pairing; self-hosted shops on GKE substitute Open Match cleanly. Proprietary matchmakers are the exception: budget the harness engineer-week for a custom protocol client regardless of which load tool you pick, because the create→accept→join→heartbeat→disconnect adapter is the work — the generator is a commodity.

| Band | Trigger | Action |
| --- | --- | --- |
| Go | p95 queue ≤60 s AND match-accept rate at target AND server tick deviation within tolerance, sustained 30 consecutive minutes at 500 CCU | Ship |
| Conditional-Go | p95 in the 60–90 s band, accept rate still at target | Launch only with named mitigations — region merging, wider party handling |
| No-Go | p95 above 90 s, or any accept rate below target, or tick deviation beyond tolerance | Block launch; producer opens the remediation backlog |

Ownership closes the loop: the live-ops lead signs the go/no-go, the producer owns the remediation backlog on any No-Go, and the gate reruns weekly through closed beta and on every matchmaking-touching patch. A passing run older than one patch cycle is void.

A green soak result is an upper bound, not a forecast. Protocol bots accept matches in milliseconds; real players take 3–15 seconds, and a fraction never accept at all. Run the arithmetic: a bot-clean 45-second p95 plausibly degrades to 70–90 seconds under human accept curves, because every stalled acceptance pins a ticket open and thins the matchable pool. Every bot-fill figure you report to a go/no-go review should carry that label — structurally optimistic by construction.

| # | If… | Then… |
| --- | --- | --- |
| 1 | Estate is Azure/Kubernetes | Standardize on PlayFab Matchmaking + Agones + k6: ~1 engineer-week setup, minimal compute per 500-CCU run |
| 2 | Estate is self-hosted on GKE | Substitute Open Match; the same harness week and minimal-compute run economics carry over |
| 3 | Matchmaker is proprietary | Budget the custom protocol-client engineer-week first; never substitute outsourced crowdtest runs for it |
| 4 | Run holds p95 ≤60 s for 30 minutes at 500 CCU with accept rate at target and tick deviation within tolerance | Live-ops lead signs Go; p95 drifting into the 60–90 s band means Conditional-Go with region merging or wider-party handling named |
| 5 | Accept rate falls below target, or p95 exceeds 90 s | No-Go; producer owns the backlog; rerun weekly through closed beta and after every matchmaking-touching patch — a pass older than one patch cycle is void |

![Choosing the Stack — k6 Harness](https://static.mm-ais.com/article-images-pixabay/k6-harness-fraction-cent-costs-sizing-ti-07b3e26e.jpg)

## What the Data Doesn't Tell You

Party size is the second structural gap. Bot populations file solo tickets by default, while co-op titles commonly see a large share of arrivals in parties of two to four — and parties fragment the pool exactly the way regions and platforms do. Queue time scales superlinearly with fragmentation, which is where the classic playtest myth dies: matching 10 humans in under 15 seconds proves nothing about 500 concurrent players, where those same slices routinely push waits past 90 seconds. Unless the harness parameterizes party mix, the run never tested the dominant real-world queue shape.

Then there is the code path that never executes. Bots seeded with uniform skill values sit inside tight rating bands, so wide-band fallback logic — the escape hatch that widens search when a band runs dry — fires zero times in a standard run. Real MMR distributions are tail-heavy, and tails are precisely what triggers that fallback. The routine most likely to multiply queue times at launch is the one your soak provably never touched.

Overwatch 2 is the standing counter-case. Blizzard ran extensive pre-launch functional testing, yet the October 2022 launch-day queues blew out anyway under DDoS pressure and account-migration load — Blizzard acknowledged this publicly. A green synthetic run certifies only the paths it exercised, never the launch-day environment surrounding them.

| Blind spot | What the soak shows | What launch day adds | Harness fix |
| --- | --- | --- | --- |
| Accept latency | Bots accept in milliseconds | Humans take 3–15 s; some never accept | Humanized accept curves plus abandon rate |
| Party mix | Solo tickets only | A large share of arrivals in parties of 2–4 | Parameterize the party-size distribution |
| MMR spread | Uniform skill; fallback fires 0 times | Tail-heavy ratings trigger wide-band logic | Seed a skewed skill distribution |
| Arrival shape | Flat 30-minute steady state | 5–10× spike in arrivals | Add a stepped burst-profile stage |
| Network path | Datacenter LAN, single-digit-ms RTT | Mobile flaps, reconnect storms, retries | Fault injection on latency and loss |

Arrival shape fails the same way. A flat soak models steady state, but free-to-play launches routinely spike 5–10× baseline arrivals in the first hour, so a passing run makes no claim about the burst-scale load that lands on day one. According to prerender.info's operational notes, the first month of real service typically introduces traffic bursts and queue backlog that were never in the original estimate — a pattern that predates games and will outlive them.

The network itself is absent by construction: protocol bots run datacenter-LAN clean at single-digit-millisecond RTT, so reconnect storms, mobile-network flaps, and retry amplification — failure modes that cascade straight back into queue depth — stay invisible to the harness. Scrapfly's February 2026 write-up on automation at scale documents the same law off-domain: scripts that behave locally leak memory and spawn runaway processes in production. None of this overturns the gate above; it defines what a pass does not certify. Before signing any Conditional-Go, name the mitigation for each row — humanized accepts, party mix, MMR tails, burst stage, fault injection. A soak that clears the bar is necessary evidence. It is never sufficient context.

Project Kestrel's most revealing number wasn't a queue time — it was 31.25. That is 500 CCU divided by 16 slots per lobby, and the fraction is the point: you cannot run 31.25 servers, so capacity planning rounds up to 32 lobbies while matchmaking behaves as if the remainder exists. Kestrel, an 8v8 team shooter preparing a February 2026 open beta, ran its go/no-go soak on PlayFab Matchmaking, Agones on GKE, and k6 protocol bots across NA-East, NA-West, and EU, with a party mix assumed in every ticket profile.

## Project Kestrel

The turnover arithmetic explains why the plateau, not the individual lobby, is the stressor. Holding 500 concurrent players against an 18-minute average session demands roughly 28 joins per minute globally — about 9.3 per region. Fill a fresh 16-slot lobby at 9.3 joins per minute and the wait to launch stretches well past a minute. That naive figure is precisely what a 10-human playtest cannot see: ten players in one room match in seconds and prove nothing about a pool fragmented across three regions and party sizes, where waits scale superlinearly as slices thin out. Partial-lobby batching — dropping tickets into lobbies that are already partly populated rather than holding out for clean rosters — pulls realistic fill down to 35–45 seconds.

The ramp was scripted, not improvised:

The hour produced thousands of tickets at a 97.2% accept rate. Sixty-one abandoned tickets were requeued and absorbed without distorting the plateau — resilience evidence no human session of comparable size has ever supplied, because requeue churn at this volume simply cannot be convened.

| Clock | Target CCU | Composition |
| --- | --- | --- |
| t+0 | 50 | 10 humans + 40 protocol bots |
| t+10m | Intermediate plateau | stepped bot-fill |
| t+20m | Next intermediate plateau | stepped bot-fill |
| t+30m | 500 | held flat through t+60m — the gate's 30 consecutive minutes at plateau |

Scored against the gate:

Verdict: Go under the global band, with EU carried as a Conditional item. Its p95 breach is most plausibly a fragmentation effect in the thinnest regional queue pool, and the named mitigation is a region-merge review scheduled before open beta — the Conditional-Go branch of the rule doing exactly what it exists to do.

| Metric | Observed | Gate read |
| --- | --- | --- |
| Global p50 queue | 22 s | comfortable margin |
| Global p95 queue | 58 s | pass under the ≤60 s band |
| EU p95 queue | 71 s | worst region — flagged |
| Peak server tick deviation | 7.4% | server side stable |

Verdict discipline, not telemetry volume, separates studios that ship matchmaking from studios that apologize for it. A soak produces two artifacts: the run log and the call you make on it. Most failed launches trace to the second artifact — someone read a healthy mean off a compromised run and signed. The five rules below each close a specific way a clean-looking number lies to you.

Start by killing the verdict everyone brings to the table: our ten-person playtest matched in under fifteen seconds, so we're fine. Queue time scales superlinearly with pool fragmentation — regions, platforms, and party sizes carve one big pool into thin slices — and a fifteen-second wait at ten players routinely becomes ninety-plus seconds at 500 CCU. The playtest anecdote measures nothing about the distribution you're shipping into, which is why every rule below gates on tail behavior across a sustained plateau rather than on a single-sample story.

## How to Choose Well

**Rule 1 — Never sign on the mean.** Gate exclusively on p95 queue time measured across the full 30-minute plateau at 500 CCU. Healthy-looking averages routinely conceal a collapsing tail, and the tail is exactly what launch day serves your newest players. A run whose mean sits comfortably low while p95 drifts past 60 seconds is a No-Go, not a watch item.

**Rule 2 — Reject any run whose bots stopped short of the accept step.** The full ticket lifecycle — create, accept, join, heartbeat, disconnect — is the unit of validity. A harness that ends at ticket creation leaks phantom requeues: unaccepted tickets cycle back into the queue, inflating apparent demand and painting a false picture of fill efficiency. Void the run no matter how clean the printed numbers look, and rerun.

**Rule 3 — Parameterize party mix before trusting any number.** Parties match as atomic units and drain a pool faster than solo tickets of equal headcount. If the harness cannot inject 2–4-player parties at your game's real ratio, downgrade the result to "optimistic bound" and widen your No-Go band accordingly — do not treat that p95 as gospel.

**Rule 4 — Add one burst scenario to every soak.** Drive 0→500 CCU inside 5 minutes and read burst p95 separately. If burst queue times blow out even while the steady-state soak passes, the verdict is Conditional-Go requiring queue-position messaging or admission backpressure before launch. Steady-state success does not excuse burst failure; day-one traffic arrives as a ramp, not a plateau.

**Rule 5 — Issue verdicts per region, never globally.** Players experience one region's queue, not the global average. A worldwide Go with any single region above 75 seconds p95 is a Conditional-Go demanding a named mitigation — pool merging or cross-region fallback — attached to that region specifically.

The next action is administrative but non-negotiable: bring this table to your gate review and require whoever ran the soak to point at one row per verdict. A call that cannot name its row — which rule fired, on which metric, in which region — is not a verdict; it is a hope with a signature on it.

**Rule 5 — Issue verdicts per region, never globally.** Players experience one region's queue, not the global average. A worldwide Go with any single region above 75 seconds p95 is a Conditional-Go demanding a named mitigation — pool merging or cross-region fallback — attached to that region specifically.

| Run observation | Rule fired | Verdict |
| --- | --- | --- |
| Mean looks healthy, p95 breaches 60 s anywhere in the 30-minute plateau | 1 | No-Go |
| Bots halt at ticket creation; accept step never executed | 2 | Void — rerun |
| Solo-only injection; no 2–4-player parties at real ratio | 3 | Optimistic bound — widen No-Go band |
| Steady soak passes, burst p95 blows out on the 5-minute ramp | 4 Frequently Asked Questions How much RAM should I provision per automated browser client? Each rendered Chrome client typically claims 1-2 GB of RAM before CPU ever becomes the binding constraint, so size the fleet by memory rather than core count. Besides the fraction-of-a-cent compute, what does it actually cost to operate a bot pool day to day? Plan on 0.2-0.5 FTE of platform time, plus first-month surprises like browser crashes, stale-output incidents, and queue backlogs that no original estimate included. My soak held steady early in the run but collapsed late — does that mean the hardware was dying? No — a soak that holds early and collapses late is usually abandoned tickets leaking back into the pool because the harness skipped the ACCEPT step, which defers queue pressure and masquerades as instability rather than dying hardware. Why can't I just have each bot start a stopwatch when it creates its matchmaking ticket? A bot starting its stopwatch at ticket creation cannot see the Open Match Director sitting idle between its default 10-second ticks, so client-side timers alone miss server-side batching delay. How many dedicated game servers does a 500-CCU soak actually consume? Roughly 32 dedicated servers, which sits comfortably inside the proven capacity of a single Kubernetes cluster under Agones' scaling write-ups. Is there a published baseline I can judge my 500-CCU p95 queue time against? PlayFab's Matchmaking documentation targets matches in roughly 30 seconds or less for casual pools, so a result sitting far above that figure owes reviewers a named reason such as party-size mix or regional thinness. Quick answers Why should a bot fleet be sized by memory rather than CPU? | Because Chrome typically needs 1-2 GB of RAM per rendered client, so a soak harness provisioned by core count hits host memory limits first and forces overprovisioning during peak windows. |
| Why does the naive fraction-cent spreadsheet estimate fail? | It models sessions multiplied by cloud CPU pricing and concludes DIY costs almost nothing, but visible Chrome compute is usually the smallest number in the spreadsheet. |  |
| What does running an automated-client pool cost in people, and what surprises arrive first month? | It takes 0.2-0.5 FTE of platform time, and the first month typically introduces browser crashes, stale-output incidents, queue backlogs, traffic bursts, and on-call work absent from the original estimate. |  |
| What is the queue-time batching formula and its example? | Expected wait ≈ lobby_size ÷ (arrival_rate × fill_efficiency), so a 16-slot lobby fed by 32 arrivals per minute fills in roughly 30 seconds at perfect efficiency — which is why adding server boxes does nothing for a slow queue. |  |
| What are the soak bounds for a 500-CCU run in terms of servers and load-generator capacity? | A 500-CCU soak consumes roughly 32 dedicated servers, comfortably inside Agones' proven envelope, and according to Grafana's k6 documentation the full 500-CCU matrix fits inside one adequately provisioned instance several times over. |  |

Also worth reading: **AWS GameLift Local Zones: $0 Egress, Yet 500-Node Fleets Fail**: [AWS GameLift Local Zones: $0](https://semble.games/blog/aws-gamelift-local-zones-0-egress-yet-500-node-fleets-fail.php) · **Rollback Netcode: Free GGPO, Photon Fusion, and One Winner**: [Rollback Netcode: Free GGPO, Photon](https://semble.games/blog/rollback-netcode-free-ggpo-photon-fusion-and-one-winner.php)

### Related reading

- [Netcode Tests vs. Real Lag: Why 100ms Spikes Slip Through](https://semble.games/blog/netcode-tests-vs-real-lag-why-100ms-spikes-slip-through.php)
- [AWS GameLift Local Zones: $0 Egress, Yet 500-Node Fleets Fail](https://semble.games/blog/aws-gamelift-local-zones-0-egress-yet-500-node-fleets-fail.php)
- [Redis vs DynamoDB TTL: Only One Engine Truly Expires](https://semble.games/blog/redis-vs-dynamodb-ttl-only-one-engine-truly-expires.php)
- [Switching Strategy Games from Rollback to Deterministic Lockstep](https://semble.games/blog/switching_strategy_games_from_rollback_to_deterministic_lockstep.php)
- [Set Autoscale at 70% CPU to Prevent Launch Crashes](https://semble.games/blog/set-autoscale-at-70-cpu-to-prevent-launch-crashes.php)
- [Unity vs Unreal: Cache, GC, Serialization Limits at 10k Users](https://semble.games/blog/unity-vs-unreal-cache-gc-serialization-limits-at-10k-users.php)

### Latest

- [Netcode Tests vs. Real Lag: Why 100ms Spikes Slip Through](https://semble.games/blog/netcode-tests-vs-real-lag-why-100ms-spikes-slip-through.php)
- [AWS GameLift Local Zones: $0 Egress, Yet 500-Node Fleets Fail](https://semble.games/blog/aws-gamelift-local-zones-0-egress-yet-500-node-fleets-fail.php)
- [Redis vs DynamoDB TTL: Only One Engine Truly Expires](https://semble.games/blog/redis-vs-dynamodb-ttl-only-one-engine-truly-expires.php)
- [Switching Strategy Games from Rollback to Deterministic Lockstep](https://semble.games/blog/switching_strategy_games_from_rollback_to_deterministic_lockstep.php)

Canonical: https://semble.games/blog/k6-harness-fraction-cent-costs-sizing-tickets-soak-bounds.php
Markdown: https://semble.games/blog/k6-harness-fraction-cent-costs-sizing-tickets-soak-bounds.php/index.md
