Designing Data-Intensive Applications
Case 6

Game Servers and State Sync

Dedicated simulation loop owns truth; clients send inputs, receive state deltas.

Diagram

Step-by-step walkthrough

Control plane — matchmaking

  • ① Enqueue ticket — Each player submits skill rating and region preference to the matchmaker.
  • ② Skill + region bucket — Matchmaker groups compatible players in Redis sorted sets.
  • ③ Allocate pod — Agones/Kubernetes spins up or assigns a dedicated game server pod.
  • ④ Return host:port — Players receive UDP endpoint; RTT kept low by regional placement.

Data plane — live match

  • ⑤ Input / state delta — Clients send inputs at 20–128 Hz; server broadcasts compressed state deltas.
  • ⑥ Fire-and-forget events — Telemetry (kills, crashes) streams to Kafka without blocking the tick loop.
Diagram
Diagram
typescript — Authoritative tick with input buffer
// Authoritative server simulation loop
let tick = 0;
const inputs: Input[] = [];

function simLoop() {
  const snapshot = applyPhysics(world, inputs.splice(0));
  broadcastDelta(clients, diff(previous, snapshot));
  previous = snapshot;
  tick++;
}
setInterval(simLoop, 1000 / 60); // 60 Hz
Fortnite at scale

Epic runs regional game server fleets; matchmaking minimizes RTT. Client sends inputs; server corrects position if client prediction diverges.

Why these technologies?

Why UDP (game traffic)?

TCP head-of-line blocking adds latency unsuitable for 60 Hz shooters. UDP drops packets — game state corrects on next tick. TCP/HTTP fine for lobby and matchmaking.

Why Authoritative game server?

Server simulates truth; clients predict locally then reconcile. Prevents speed hacks and wall hacks — P2P cannot enforce fairness in competitive games.

Why Matchmaker service?

Groups players by skill (MMR) and region (ping). Separate from game simulation — queue logic changes without redeploying game binaries.

Why Agones / Kubernetes game pods?

Each match is an isolated process with dedicated CPU — natural scale unit. Spin up pod per match, tear down after. StatefulSet assigns stable UDP ports.

Why In-memory state (not Postgres during match)?

Sub-16 ms tick loops cannot round-trip to disk. Checkpoint stats to DB only after match ends. Redis optional for cross-service lobby state.

Why Kafka (telemetry)?

Fire-and-forget analytics: kills, crashes, latency histograms. Never blocks the game tick loop.

Why Not a single global game database?

Game state is ephemeral and regional — sharding by match ID, not user ID.

Key Takeaways
  • Lobby service assigns players to a game server instance.
  • Server sim loop: inputs in → physics/rules → state snapshot out.
  • Delta compression sends only changed entities to clients.
  • Redis or in-memory store for session; periodic checkpoint to DB for stats.
  • Dedicated servers vs P2P: commercial titles choose servers for anti-cheat.
  • Agones on Kubernetes scales game server pods per match.
game serverdelta compressionAgonesKubernetespredictionUDPKafka