Skip to content

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 next to the server shows you a best case that no real player sees. This page shows how to use MaxoPerf’s multi-region runner selection and k6 environment variables to model realistic, degraded 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, for these reasons:

  • 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 processes the packet. Add server processing time and the total RTT passes 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 tests that run only from high-bandwidth origins miss this constraint.

To add geographic realism to a game load test, select several 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:

LocationVU shareBase RTT to US-East server
us-east-140 %~5 ms
us-west-225 %~60 ms
eu-west-120 %~80 ms
ap-southeast-115 %~150 ms

This distribution generates load from a realistic global player base. With the per-region latency charts in MaxoPerf, you compare player experience across locations in the same run instead of 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. It does not model packet loss, bandwidth caps or mobile jitter within a region. For these conditions, inject artificial delays in the k6 script with environment variables:

network-conditions.js
import ws from 'k6/ws';
import { sleep } from 'k6';
// Injected via MaxoPerf secrets/env vars per run
const 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 nameEXTRA_LATENCY_MSLOSS_RATEModels
baseline00Co-located players
mobile-4g400.01Mobile broadband, ~1 % loss
poor-connection1200.03Rural broadband, ~3 % loss
satellite6000.02Satellite 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.

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.js

This runs a 4-hour soak with mobile-like conditions. A long run like this surfaces memory leaks in the server’s per-connection state under degraded ack rates.

  • Per-region latency divergence. On the Overview tab, filter by location. Each region’s p95 should track its realistic base RTT plus server processing. If eu-west-1 p95 is 300 ms when us-east-1 is 30 ms, check whether the server applies geographic routing or sends all traffic through a single east-coast endpoint.
  • Error rate under loss. Artificial packet loss should not produce server errors in a WebSocket-over-TCP test, because 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_duration in the metrics panel. Sessions should hold for the configured socket.setTimeout duration even under simulated loss. Sessions that end early point to timeout thresholds tuned only for fiber connections.

Do:

  • Include at least one distant runner region so your test shows real geographic latency instead of 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 network conditions cost your players.

Don’t:

  • Use artificial sleep() delays as a replacement for multi-region runners. sleep() adds latency uniformly inside the k6 event loop and does not model real TCP network path variance.
  • Run degraded-network load tests only once. Network profiles should be part of every pre-release regression suite.