Game infrastructure

Game backend architecture for 50,000 concurrent players

What the stack looks like, why each part is there, and the four things that break first on the way up.

Short answer. A backend that holds 50,000 concurrent players is built from four separable parts: stateless edge services that terminate player connections, authoritative session services that own game state, a low-latency event fabric between them, and an autoscaler driven by connection count rather than CPU. In a live mobile title we built this way, the result was 52,000 peak concurrent players at 62 ms average latency and 99.98% uptime. The architecture matters less than one decision inside it: which service owns a given piece of state, and whether anything else is allowed to write it.

Why 50,000 concurrent is a different problem, not a bigger one

A backend for 500 concurrent players and a backend for 50,000 are not the same system scaled by 100. Below roughly 2,000 CCU almost any reasonable design works — a single application server with an in-process session map and a relational database will hold it, and most of the engineering effort goes into gameplay features rather than infrastructure.

Somewhere between 5,000 and 10,000 the assumptions start failing one at a time, and they fail in a specific order. Knowing that order is most of the value of having done it before, because each failure is cheap to design around in advance and expensive to retrofit under live traffic.

Concretely, what changes:

What the architecture actually looks like

The stack below is the one behind the numbers in the first paragraph. It is deliberately unexotic: every part is a well-understood component doing one job, because a game backend is operated by a live-ops team at three in the morning and cleverness is a liability at that hour.

1. Stateless edge — connection termination

Player connections terminate on a horizontally scalable tier that holds no game state at all. Its only jobs are transport, authentication, and routing messages onward. Because it is stateless it can scale purely on connection count and can be replaced instance by instance without anyone noticing.

The discipline here is negative: the moment the edge tier starts caching "just a little" player state to save a hop, you have re-created the single-process problem across N boxes, and now it is a distributed consistency bug instead of a simple one.

2. Authoritative session services — one writer per piece of state

Game state lives in services that own it exclusively. A match, a session, a player inventory: each has exactly one authority, and every mutation goes through it. This is the single most important decision in the whole design, and it is the one most often compromised under deadline pressure.

The payoff is that the hard problems — duplicate item grants, rubber-banding, two clients disagreeing about who won — become impossible by construction rather than being fixed with locks and retries after they show up in production. We build these in Go, with gRPC between services: goroutine-per-session is a natural fit for tens of thousands of concurrent sessions, and the garbage collector's latency profile is predictable enough to sit in a gameplay path.

3. A Redis-backed event fabric

Between the tiers sits Redis, doing pub/sub for fan-out and queue patterns for work that must not be lost — matchmaking coordination, cross-service notification, presence. Redis is chosen here for latency floor rather than features: sub-millisecond at the p99 in-region, with an operational model any on-call engineer already understands.

A common and expensive mistake is putting a general-purpose message broker in the gameplay path because it appeared on an architecture diagram. Durability guarantees cost latency. Use the durable path for things that must survive a crash — purchases, match results, progression — and the fast path for things that are stale in 50 ms anyway, like position updates.

4. Autoscaling on the right signal

The runtime is Kubernetes, with scaling rules driven by connection count and matchmaking queue depth rather than CPU utilisation. This is the correction almost every game backend needs at some point: CPU is a lagging indicator for a connection-bound workload, and by the time it moves, the queue is already deep enough that players are feeling it.

Observability is Grafana on metrics the live-ops team chose, not the ones that were easy to emit. The test of a dashboard is whether someone can answer "is the game healthy right now" in under ten seconds without asking an engineer.

Players — game clients Stateless edge — connections only, no game state Redis — pub/sub and durable queues PostgreSQL — progression, purchases Authoritative session services exactly one writer per piece of state connect, authenticate fast path, lossy durable path match events writes
Every mutation to game state goes through one authority. The edge tier holds connections and nothing else — the moment it caches "just a little" player state, the single-writer property is gone and the hard bugs come back.

What breaks first, in order

Roughly whenWhat breaksWhat it costs to fix later
2k–5k CCU In-process session state prevents horizontal scaling High — it is a re-architecture of the service boundary, not a change
5k–10k CCU Write contention on hot tables (leaderboards, inventory, match results) Medium — usually solved by moving the hot path off the relational store
10k–20k CCU CPU-based autoscaling reacts too late for connection-bound load Low — a scaling policy change, if the metrics already exist
20k+ CCU Deploys become player-visible; no session drain, no graceful handover Medium — needs connection draining and version-tolerant protocol
Any scale, event spikes Cold-start latency on scale-out during a burst Low — pre-warming and headroom, once someone has measured it

How do you know it actually holds?

You load-test continuously during delivery, not in the final week. This is the practice that separates backends that hit their CCU target from backends that were designed to.

On the project behind these numbers, load simulation ran throughout the build rather than as a release gate, which is why the first real traffic peak was uneventful. The sequence that worked:

  1. Map the domain first. Separate gameplay-critical paths from live-ops paths, so the architecture can prioritise the ones players feel.
  2. Build one vertical slice. Matchmaking and session orchestration end to end, before widening into adjacent concerns.
  3. Simulate load from that point on. Every sprint, against the real protocol, at a multiple of the target.
  4. Roll out observability before you need it. Dashboards and alerts handed to the live-ops team well before launch, so they are familiar rather than novel during the first peak.
  5. Harden the deploy path. Autoscaling and release controls tuned so a patch during an event is routine.

A target of "50,000 CCU" is also worth interrogating before you design for it. Peak concurrency is what the infrastructure must survive, and it is frequently confused with monthly actives or registered users — which are unrelated numbers, often two orders of magnitude apart. Designing for a peak you will not reach for two years is the most common way to overspend on a game backend; see what drives the number for the rest of that list.

What this does not cover

Deliberately out of scope above, because each is its own decision: authoritative physics and rollback netcode (a client-engine concern more than a backend one — see Unity or Unreal for a multiplayer game), anti-cheat, regional sharding and cross-region matchmaking, and on-chain asset ownership if the title has any (what actually belongs on-chain).

The full delivery story for the numbers quoted here — client context, delivery scope, and measured outcome — is in the multiplayer game backend case study.

Scoping a backend that has to hold up?

We will review your concurrency target, your architecture, and your launch window, and tell you honestly which of the five failure modes above you are currently pointed at.

Message received

We’ll review your enquiry and respond within one business day.

Related reading