Network emulation conditions
Real players do not connect from a data center with a sub-millisecond network path to your game server. They connect over mobile networks with 80 ms base RTT, from rural regions with higher jitter, or through ISP congestion that causes occasional packet loss. A load test that runs only from a single cloud region co-located with the server gives you a best-case scenario that no real player will experience. This page shows how to use MaxoPerf’s multi-region runner selection and k6 environment variables to model realistic, degraded network conditions.
Before you start
Section titled “Before you start”- Read Latency, jitter, and packet loss — understand which metrics to watch before layering in network emulation.
- Read Game server load testing — you need a working baseline load test before adding network conditions.
Why network conditions matter for game load tests
Section titled “Why network conditions matter for game load tests”A game server that performs perfectly in a data-center-to-data-center load test can still fail players because:
- Regional latency adds to server RTT. A player in São Paulo connecting to a US-East server has a baseline 130–150 ms network RTT before the server even processes the packet. Combined with server processing time, this pushes the total RTT past the competitive threshold.
- Mobile and broadband variance exposes jitter sensitivity. Mobile connections add random latency spikes from tower handoffs and congestion. A server that handles 1 000 players from a fiber connection may degrade visibly when those same players are on 4G.
- Bandwidth-constrained paths affect message size budgets. Games sending large world-state messages may hit bandwidth limits on constrained connections before they hit server CPU limits. Load testing only from high-bandwidth origins misses this constraint entirely.
Multi-region runners in MaxoPerf
Section titled “Multi-region runners in MaxoPerf”The simplest way to add geographic realism to a game load test is to select multiple runner locations that match your real player distribution. MaxoPerf splits the configured VU count across locations proportionally unless you assign a per-location weight.
In the MaxoPerf console, go to Test configuration → Locations and select:
- The region closest to your game server (for the “ideal” segment of players).
- One or more distant regions (for players with higher base latency).
Example distribution for a North American game server:
| Location | VU share | Base RTT to US-East server |
|---|---|---|
us-east-1 | 40 % | ~5 ms |
us-west-2 | 25 % | ~60 ms |
eu-west-1 | 20 % | ~80 ms |
ap-southeast-1 | 15 % | ~150 ms |
This distribution generates load that reflects a realistic global player base. The per-region latency charts in MaxoPerf let you compare player experience across locations in the same run — without running four separate tests.
import Screenshot from ‘@components/Screenshot.astro’;
Simulating degraded conditions with k6 environment variables
Section titled “Simulating degraded conditions with k6 environment variables”Geographic distribution gives you realistic base latency, but it does not model packet loss, bandwidth caps, or mobile jitter within a region. For these conditions, inject artificial delays in the k6 script using environment variables:
import ws from 'k6/ws';import { sleep } from 'k6';
// Injected via MaxoPerf secrets/env vars per runconst EXTRA_LATENCY_MS = parseInt(__ENV.EXTRA_LATENCY_MS || '0', 10);const LOSS_RATE = parseFloat(__ENV.LOSS_RATE || '0');
export default function () { ws.connect( `wss://game.staging.example.com/ws?token=${__ENV.GAME_TOKEN}`, {}, function (socket) { socket.on('open', () => { socket.send(JSON.stringify({ type: 'join', zone: 'world-1' })); });
socket.on('message', (data) => { // Simulate extra latency before processing if (EXTRA_LATENCY_MS > 0) { sleep(EXTRA_LATENCY_MS / 1000); }
// Simulate packet loss — drop this message without processing if (LOSS_RATE > 0 && Math.random() < LOSS_RATE) { return; }
// Normal message handling ... const msg = JSON.parse(data); socket.send(JSON.stringify({ type: 'ack', seq: msg.seq })); });
socket.setTimeout(() => socket.close(), 120000); } );}Define test runs for different conditions:
| Run name | EXTRA_LATENCY_MS | LOSS_RATE | Models |
|---|---|---|---|
baseline | 0 | 0 | Co-located players |
mobile-4g | 40 | 0.01 | Mobile broadband, ~1 % loss |
poor-connection | 120 | 0.03 | Rural broadband, ~3 % loss |
satellite | 600 | 0.02 | Satellite internet |
Add EXTRA_LATENCY_MS and LOSS_RATE as MaxoPerf environment variables in the
Secrets / Environment tab, then clone the test for each condition profile.
Taurus YAML for a degraded-network soak
Section titled “Taurus YAML for a degraded-network soak”For a longer degraded-network test, use Taurus to wrap the k6 script with a realistic hold duration:
execution: - executor: k6 concurrency: 300 ramp-up: 2m hold-for: 4h env: EXTRA_LATENCY_MS: "40" LOSS_RATE: "0.01" scenario: mobile-soak
scenarios: mobile-soak: script: network-conditions.jsThis runs a 4-hour soak with mobile-like conditions — the kind of long-running test that will surface memory leaks in the server’s per-connection state under degraded ack rates.
What to look for
Section titled “What to look for”- Per-region latency divergence. On the Overview tab, filter by location. Each region’s
p95 should reflect its realistic base RTT plus server processing. If
eu-west-1p95 is 300 ms whenus-east-1is 30 ms, investigate whether the server applies geographic routing or whether all traffic goes through a single east-coast endpoint. - Error rate under loss. Artificial packet loss should not produce server errors in a
WebSocket-over-TCP test — TCP retransmission handles loss transparently. If error rates
climb with
LOSS_RATE, the server has a timeout sensitivity that needs tuning. - Session duration under mobile conditions. Check
ws_session_durationin the metrics panel. Sessions should hold for the configuredsocket.setTimeoutduration even under simulated loss. Premature session terminations indicate timeout thresholds tuned for fiber connections only.
Do / don’t
Section titled “Do / don’t”Do:
- Always include at least one distant runner region to ensure your test reflects real geographic latency, not data-center-to-data-center latency.
- Name each degraded-condition run clearly (e.g.
v1.4.2-mobile-4g-soak) so comparisons across releases are meaningful. - Use MaxoPerf’s run-comparison feature to diff a clean-network baseline against a degraded-network run — the delta is what real-world player experience costs you.
Don’t:
- Use artificial
sleep()delays as a replacement for multi-region runners —sleep()adds latency uniformly inside the k6 event loop, which does not model actual TCP network path variance accurately. - Run degraded-network load tests only once. Network profiles should be part of every pre-release regression suite.
Where to go next
Section titled “Where to go next”- Latency, jitter, and packet loss — what the metrics mean.
- Multi-region run — full MaxoPerf multi-location configuration guide.
- Launch spike and soak — test degraded conditions during peak load.
- Daily scenarios — when to run each network condition profile.