Skip to content

Game & network load testing — do and don't

This page is a quick reference of the most common mistakes in game and network load testing and the correct approach for each. Use it as a pre-run checklist before any game performance test in MaxoPerf.


Do: hold WebSocket connections open for a realistic session duration. Game player sessions last 2–30 minutes, not 10 seconds. Use socket.setTimeout() inside the k6 WebSocket handler to hold each virtual user’s connection for the target session duration (e.g. 5 min). Short connect/disconnect cycles test connection setup throughput, not steady-state player load — they will not reveal memory leaks or tick-rate degradation.

Don’t: treat a successful WebSocket handshake as a passed game server test. ws_connecting p95 measures TCP handshake time. It does not measure game-loop latency, message processing throughput, or session stability under sustained load. Always add custom Trend metrics for message RTT and use them as the primary pass/fail signal.


Do: set explicit failure criteria before running. Define p(95) and avg thresholds for ws_connecting, game_msg_latency_ms, and error rate in the k6 options.thresholds block. MaxoPerf will fail the run automatically if any threshold is violated — you should never be manually deciding “is 420 ms acceptable?” at midnight before a launch.

Don’t: use mean (average) latency as the headline game quality metric. Means hide the tail that players experience as lag spikes. A 30 ms mean RTT with a p99 of 800 ms is a badly performing server. Always report p95 and p99 alongside the mean, and set thresholds on both.


Do: ramp the spike within 30 seconds to simulate a launch storm or event spike. Real game launch traffic arrives in under a minute — thousands of players click “Play” at the moment the game goes live. A 10-minute ramp-up hides the launch-day failure mode. For launch simulation, use ramp-up: 30s in the Taurus YAML stages config.

Don’t: run only a spike without a recovery observation window. The recovery window (2–3 minutes after the VU count drops back to baseline) reveals whether the system truly recovers or continues to show elevated errors due to resource exhaustion. A system that “survived” the spike but continued showing 5xx responses for 20 minutes afterward has not passed the launch-readiness test.


Do: use multiple MaxoPerf runner locations matching your real player distribution. Game players connect from everywhere. A single-region load test from the data center nearest your server gives best-case latency that no real player will see. Always add at least one geographically distant runner location (e.g. EU runners for a US server) to expose the regional latency gap.

Don’t: infer UDP game server capacity from a WebSocket load test alone. WebSocket runs on TCP; UDP game servers have different congestion, reordering, and loss characteristics. Use WebSocket tests for services that genuinely use WebSocket. For UDP-based game protocols, test the control plane in MaxoPerf and validate the data plane separately with a UDP-capable tool.


Do: use unique player identities (player IDs, tokens) per virtual user. Most game services — matchmaking, leaderboards, inventory — deduplicate by player ID. If all 1 000 virtual users share one token, the server processes 1 000 requests from a single player, which triggers rate-limiting and deduplication paths that a real launch would not hit. Use a CSV data entity with one token per row, cycling with __VU % tokens.length.

Don’t: use production player accounts as load-test identities. Load tests write data: scores, session records, inventory mutations, matchmaking tickets. Running a 5 000-VU test with real player tokens will pollute real player data, trigger notifications, affect leaderboard rankings, and potentially trigger anti-cheat detection. Always provision dedicated loadtest accounts with the same permission set as real players.


Do: include party (group) tokens in matchmaking test data. Solo matchmaking tests miss the combinatorial overhead of group matchmaking. A realistic test mixes solo and party enqueues (roughly 60 %/40 % for most titles). Pre-generate party tokens server-side and upload them as a MaxoPerf data entity.

Don’t: skip the session-join step in a matchmaking test. Issuing a queue ticket and measuring queue wait time is only half the funnel. If the match is formed but the session-join fails (e.g. session server is overloaded), players still cannot play. Always complete the full enqueue → match → join sequence in the test.


Do: run the overnight soak at steady-state VU count, not spike VU count. A soak test at spike levels is a stress test, not a stability test. Use the same VU count as your regular load test — you are testing duration effects (leaks, drift), not maximum capacity.

Don’t: declare the soak passed just because no errors occurred. A soak that finishes with zero errors but shows a 30 % drift in p95 latency over 8 hours is a failing soak — the server is degrading, just not failing yet. Always check the Overview tab for latency drift, not just the final error count.


Do: run at least one degraded-network variant (mobile, high-latency) per pre-release cycle. Real players do not have fiber connections to your data center. A test that passes from a co-located runner but fails for players in remote regions or on mobile networks is not ready for launch. See Network emulation conditions.

Don’t: accept a clean data-center-to-data-center result as representative of global player experience. The latency numbers your co-located test reports are not what your players see. Always compare per-region latency from distant runner locations before approving a pre-launch performance result.