Čím se herní backend liší od všeho ostatního
Pokud jste někdy vyvíjeli backend pro webovou aplikaci, víte, jak to funguje: klient odešle požadavek HTTP, server jej zpracuje, dotazuje se na databázi a vrací odpověď JSON. Cyklus se opakuje každá interakce. O pár milisekund delší latence? Uživatel si toho ani nevšimne.
Un backend hry pro více hráčů žije v úplně jiném vesmíru. O tom tady nemluvíme požadavky a odpovědi: pojďme mluvit o a nepřetržitý tok obousměrných dat, kde každou milisekundu věci, kde stovky hráčů sdílejí společný stav, který se mění desítkykrát za sekundu, a kde 100 ms zpoždění může znamenat rozdíl mezi vítězstvím a porážkou.
V tomto prvním článku seriálu Herní backendové inženýrství, prozkoumáme anatomii kompletní s backendem hry pro více hráčů: od síťové architektury po komunikační protokoly, od hry smyčky na straně serveru k serializaci zpráv až po škálovací strategie a platformy Backend-as-a-Service. Na konci budete mít kompletní mentální mapu každé složky a možností architektonické problémy, se kterými se budete muset vypořádat.
Přehled série
| # | Položka | Soustředit |
|---|---|---|
| 1 | Jste zde - Anatomie herního backendu | Architektura, protokoly, komponenty |
| 2 | Synchronizace stavu | Netcode, interpolace, predikce |
| 3 | Matchmaking Engine | Algoritmy ELO, fronty, lobby |
| 4 | Dedikované herní servery | Infrastruktura a orchestrace |
| 5 | Anti-Cheat architektura | Ověření na straně serveru, detekce |
| 6 | LiveOps a monetizace | In-game ekonomika, živé akce |
| 7 | Telemetrie a analytika | Metriky, datové kanály, dashboardy |
| 8 | Pozorovatelnost | Protokolování, sledování, upozorňování |
| 9 | Cloudová herní infrastruktura | Streamování, edge computing, latence |
| 10 | Hry s otevřeným zdrojovým kódem | Nakama, Colyseus, Agones |
Co se naučíte
- Základní rozdíly mezi webovým a herním backendem
- Síťové modely: klient-server, peer-to-peer a relay
- Jak funguje herní smyčka na straně serveru (autoritativní server)
- Komunikační protokoly: TCP vs UDP vs WebSocket vs WebRTC
- Serializace zpráv: Protocol Buffers, FlatBuffers, MessagePack
- Správa připojení: relace, opětovné připojení, srdeční frekvence
- Možnosti databáze: Redis, PostgreSQL, časové řady
- Vzor škálování: lobby server, světový server, instanciované zóny
- Platformy BaaS: PlayFab, GameLift, Nakama, Colyseus
1. Webový backend vs herní backend: Dva různé světy
Abychom pochopili, proč herní backend vyžaduje radikálně odlišný přístup, porovnejme požadavky základní ve srovnání s tradičními webovými aplikacemi.
Porovnání požadavků: Web vs hra
| čekám | Webový backend | Backendová hra pro více hráčů |
|---|---|---|
| Komunikační model | Požadavek-odpověď (HTTP) | Nepřetržité obousměrné streamování |
| Přijatelná latence | 200-500 ms | 16–50 ms (jeden snímek při 60 snímcích za sekundu = 16,6 ms) |
| Frekvence aktualizace | Na vyžádání (klikněte, odešlete) | 20–128krát za sekundu (rychlost tikání) |
| Stát | Bez státní příslušnosti (každá nezávislá žádost) | Stavový (sdílený stav v paměti) |
| Konzistence | Jakákoli přijatelná konzistence | Silná konzistence v reálném čase |
| Škálovatelnost | Horizontální (vyvažovač zatížení + repliky) | Vertikální na relaci + horizontální na relaci |
| Tolerance ztráty dat | Nula (každá transakce se počítá) | Selektivní (ztracené pozice jsou v pořádku, nákupy ne) |
| Doba trvání relace | Minuty (navigace) | Hodiny (herní relace) |
| Šířka pásma na uživatele | Sporadicky KB | 5-50 KB/s nepřetržitě |
Rozhodujícím bodem je příroda stavový backendu hry. Webový server může být kdykoli vyměnit – stačí nasměrovat provoz do jiné instance. Herní server uchovává v paměti stav aktivní hry: pozice hráčů, střely v letu, aktivní efekty, skóre. Pokud tento server selže, hra je ztracena.
Problém latence ve hrách
V konkurenčním FPS při 128 tick/s server zpracovává každou aktualizaci 7,8 ms. Pokud má hráč latenci sítě 50 ms (RTT), jeho vstup dorazí na server se zpožděním 25 ms a odpověď dorazí s dalšími 25 ms. Hráč vidí svět 50 ms pozadu do reality serveru. Po 200 ms se hra stane nehratelnou. To je důvod, proč techniky, jako je predikce na straně klienta e il kompenzace zpoždění jsou zásadní.
2. Síťové modely: Jak se hráči připojují
První architektonické rozhodnutí se týká síťového modelu: jak spolu klienti komunikují a se serverem? Existují tři hlavní přístupy, z nichž každý má specifické kompromisy.
2.1 Klient-Server (autoritativní server)
Dominantní model v moderním hraní. Jeden centrální server je jediný autorita na stav hry. Klienti posílají své vstupy (stisknutí kláves, pohyby myši) na server, který validuje je, aktualizuje stav světa a výsledek posílá všem klientům. Žádný klient nemůže přímo změnit stav hry.
Client A Server Client B
| | |
|--- Input (W,A) -->| |
| |--- Input (S,D) ---|<
| | |
| [Valida input] |
| [Aggiorna stato] |
| [Rileva collisioni] |
| [Calcola risultato] |
| | |
|<-- Stato mondo ---|--- Stato mondo -->|
| | |
| [Interpola/ | [Interpola/ |
| Predici] | Predici] |
výhody: maximální zabezpečení (server vše řídí), integrovaný anti-cheat, Konzistentní stav pro všechny hráče, snadné ladění. Nevýhody: vysoké náklady na infrastrukturu (jeden server pro každou hru), latence další (každý vstup musí být zpětný), jediný bod selhání.
2.2 Peer-to-Peer (P2P)
Každý klient komunikuje přímo se všemi ostatními. Neexistuje žádný centrální server - každý hráč a jak klienta, tak "serveru" pro sebe. Tento model byl oblíbený v bojových hrách a v RTS, kde je počet hráčů omezen (2-8).
výhody: žádné náklady na server, minimální latence mezi peery (přímé připojení), přežije smrt jakéhokoli uzlu. Nevýhody: nemožné zabránit cheatům (každý klient má pravomoc nad svým vlastním státem), exponenciální složitost s počtem hráčů (N*(N-1)/2 připojení), problémy s průchodem NAT.
2.3 Relay Server (Server jako proxy)
Kompromis mezi oběma modely. Centrální server funguje jako relé: Přijímá zprávy od každého z nich klienta a přeposílá je všem ostatním, ale nezpracovává herní logiku. Simulace probíhá na klientech, serveru a jen "pošťákovi".
Porovnání síťových modelů
| Charakteristický | Klient-Server | P2P | Relé |
|---|---|---|---|
| Bezpečnost | Vysoká (autoritní server) | Nízká (žádná autorita) | Průměr (závisí na klientovi) |
| Cena serveru | Vysoký | Null | Bas |
| Škálovatelnost | Stovky hráčů | 2-8 hráčů | Desítky hráčů |
| Latence | Průměr (zpáteční) | Nízká (přímá) | Média (přes server) |
| Typické použití | FPS, MMO, Battle Royale | Bojová, klasická RTS | Kooperativní, příležitostné, mobilní |
| Příklady | Valorant, Fortnite, CS2 | Street Fighter, StarCraft | Mezi námi, podzimní kluci |
3. Herní smyčka na straně serveru
Srdcem autoritativního herního backendu je herní smyčka: opakující se cyklus a konstantní frekvence ( tick rate), zpracování vstupu, aktualizace stavu a odeslání výsledky pro klienty. Frekvence tick rate určuje "časové rozlišení" simulace.
Zaškrtněte sazbu podle žánru
| Typ | Zaškrtávací sazba | Interval | Příklad |
|---|---|---|---|
| Konkurenční FPS | 128 Hz | 7,8 ms | Valorant, CS2 |
| Standardní FPS | 64 Hz | 15,6 ms | Overwatch 2 |
| Battle Royale | 20-30Hz | 33-50 ms | Fortnite, PUBG |
| MMO | 10-20Hz | 50-100 ms | World of Warcraft |
| Strategické/Zatáčky | 1-10Hz | 100 ms-1s | Civilizace, Hearthstone |
interface PlayerInput {
readonly playerId: string;
readonly tick: number;
readonly keys: ReadonlyArray<string>;
readonly mouseX: number;
readonly mouseY: number;
readonly timestamp: number;
}
interface GameState {
readonly tick: number;
readonly players: ReadonlyMap<string, PlayerState>;
readonly projectiles: ReadonlyArray<Projectile>;
readonly timestamp: number;
}
class AuthoritativeGameServer {
private readonly TICK_RATE = 64; // 64 aggiornamenti/secondo
private readonly TICK_INTERVAL = 1000 / 64; // ~15.625ms per tick
private currentTick = 0;
private gameState: GameState;
private readonly inputBuffer: Map<string, PlayerInput[]> = new Map();
start(): void {
console.log(`Server avviato a ${this.TICK_RATE} tick/s`);
setInterval(() => this.tick(), this.TICK_INTERVAL);
}
// Riceve input dal client (chiamato dalla rete)
onPlayerInput(input: PlayerInput): void {
const buffer = this.inputBuffer.get(input.playerId) ?? [];
// Crea nuovo array invece di mutare
this.inputBuffer.set(input.playerId, [...buffer, input]);
}
private tick(): void {
const tickStart = performance.now();
this.currentTick++;
// 1. Processa tutti gli input ricevuti
const processedInputs = this.processInputs();
// 2. Aggiorna la simulazione di gioco
const updatedState = this.updateSimulation(processedInputs);
// 3. Rileva collisioni
const stateAfterCollisions = this.detectCollisions(updatedState);
// 4. Aggiorna lo stato di gioco (immutabile)
this.gameState = {
...stateAfterCollisions,
tick: this.currentTick,
timestamp: Date.now(),
};
// 5. Invia lo stato aggiornato a tutti i client
this.broadcastState(this.gameState);
// 6. Monitora le performance del tick
const tickDuration = performance.now() - tickStart;
if (tickDuration > this.TICK_INTERVAL) {
console.warn(
`Tick ${this.currentTick} overrun: ${tickDuration.toFixed(2)}ms ` +
`(budget: ${this.TICK_INTERVAL.toFixed(2)}ms)`
);
}
}
private processInputs(): Map<string, PlayerInput> {
const latest = new Map<string, PlayerInput>();
for (const [playerId, inputs] of this.inputBuffer) {
if (inputs.length > 0) {
// Prendi l'ultimo input valido
const lastInput = inputs[inputs.length - 1];
if (this.validateInput(lastInput)) {
latest.set(playerId, lastInput);
}
}
}
// Svuota il buffer (nuovo Map, non mutare)
this.inputBuffer.clear();
return latest;
}
private validateInput(input: PlayerInput): boolean {
// Anti-cheat: verifica che i valori siano plausibili
const maxSpeed = 10;
return (
Math.abs(input.mouseX) <= 360 &&
Math.abs(input.mouseY) <= 90 &&
input.keys.length <= 6
);
}
}
Zaškrtněte Rozpočet a Překročení
Při rychlosti 64 ticků/s má každé tiku a rozpočet 15,6 ms. Pokud tiká logika (fyzika, kolize, AI, networking) trvá déle, server hromadí zpoždění a hráči vnímají zpoždění. Sledování tikového rozpočtu je zásadní: ve výrobě sledujete p99 trvání klíštěte, nikoli průměr.
4. Řízení státu: Tři úrovně státu
Stav hry pro více hráčů není monolitický blob: je rozdělen do úrovní s charakteristikami a různé požadavky. Každá vrstva vyžaduje strategie ukládání, synchronizace a perzistence jiný.
Tři úrovně herního stavu
| Úroveň | Co obsahuje | Frekvence aktualizace | Perzistence | Skladování |
|---|---|---|---|---|
| Stav snímku | Polohy, rychlosti, rotace, střely | Každý tik (20-128 Hz) | Pouze v paměti | RAM herního serveru |
| Stav relace | HP, inventář, skóre, buff/debuff | Na akci (poškození, vyzvednutí) | Po dobu zápasu | RAM + Redis (záloha) |
| Trvalý stav | Profil, statistiky, nákupy, pořadí | Na konci hry nebo při transakci | Trvalý | PostgreSQL / MongoDB |
// === FRAME STATE: aggiornato ogni tick ===
interface FrameState {
readonly tick: number;
readonly entities: ReadonlyMap<string, EntityTransform>;
readonly projectiles: ReadonlyArray<ProjectileState>;
readonly effects: ReadonlyArray<ActiveEffect>;
}
interface EntityTransform {
readonly posX: number;
readonly posY: number;
readonly posZ: number;
readonly rotYaw: number;
readonly rotPitch: number;
readonly velocityX: number;
readonly velocityY: number;
readonly velocityZ: number;
}
// === SESSION STATE: aggiornato su eventi ===
interface SessionState {
readonly playerId: string;
readonly health: number;
readonly maxHealth: number;
readonly armor: number;
readonly inventory: ReadonlyArray<InventoryItem>;
readonly activeWeapon: string;
readonly kills: number;
readonly deaths: number;
readonly score: number;
readonly buffs: ReadonlyArray<BuffEffect>;
readonly team: string;
}
// === PERSISTENT STATE: salvato su database ===
interface PersistentPlayerData {
readonly odlayerId: string;
readonly username: string;
readonly elo: number;
readonly totalMatches: number;
readonly totalWins: number;
readonly totalKills: number;
readonly unlockedItems: ReadonlyArray<string>;
readonly purchaseHistory: ReadonlyArray<Purchase>;
readonly createdAt: Date;
readonly lastLoginAt: Date;
}
Rozdělení do úrovní je pro výkon zásadní. The stav rámu to musí být co nejkompaktnější, protože je serializován a odesílán všem klientům při každém zaškrtnutí. The stav relace odesílá se pouze při změně. The přetrvávající stav nikdy se nevysílá: může o to požádat pouze vlastník a uloží se asynchronně v databázi.
5. Komunikační protokoly: TCP, UDP, WebSocket, WebRTC
Volba transportního protokolu je jedním z nejpůsobivějších rozhodnutí v architektuře a herní backend. Každý protokol nabízí různé kompromisy mezi spolehlivostí, latencí a složitostí.
5.1 TCP (Transmission Control Protocol)
TCP zajišťuje řádné a spolehlivé doručení každého paketu. Pokud je paket ztracen, TCP znovu jej odešle a zablokuje doručení následujících paketů, dokud nedorazí ztracený. Toto jev se nazývá blokování hlavy a je to smrtelný nepřítel hraní v reálném čase.
5.2 UDP (User Datagram Protocol)
UDP a „vypálit a zapomenout“: Odesílejte pakety bez záruky doručení, objednávky nebo integrity. Pokud a paket je ztracen, není znovu odeslán. To zní hrozně, ale pro hru v reálném čase a přesně to, co je potřeba: pozice hráče před 100 ms a irelevantní, pokud ji máte před 16 ms.
5.3 WebSockets
WebSocket funguje nad TCP, ale poskytuje plně duplexní obousměrné připojení. A protokol standard pro hry založené na prohlížeči a mobilní hry, kde nativní UDP není k dispozici. Latence e větší než čistý UDP, ale snadná implementace a univerzální kompatibilita učinit z něj pragmatickou volbu pro mnoho žánrů.
5.4 WebRTC (DataChannel)
WebRTC DataChannel nabízí komunikaci peer-to-peer (nebo klient-server) založenou na SCTP přes UDP. Podporuje spolehlivé i nespolehlivé režimy, konfigurovatelné pro každý kanál. A jediná možnost pro získejte ve svém prohlížeči komunikaci podobnou UDP.
Porovnání síťových protokolů pro hraní her
| čekám | TCP | UDP | WebSockets | WebRTC DC |
|---|---|---|---|---|
| Doprava | TCP | UDP | TCP | SCTP/UDP |
| Garantované doručení | Si | No | Si | Konfigurovatelné |
| Zaručená objednávka | Si | No | Si | Konfigurovatelné |
| Blokování hlavičky | Si | No | Si | Ne (nespolehlivé) |
| Typická latence | Vysoká (opětovné odeslání) | Minimální | Průměrný | Nízký |
| Podpora prohlížeče | Ne (přímo) | No | Si | Si |
| NAT traversal | Není nutné | Problematický | Není nutné | Integrovaný (ICE) |
| Složitost | Nízký | Vysoká (zákaznická spolehlivost) | Nízký | Vysoká (signalizace) |
| Ideální pro | Chat, směny, lobby | FPS, závodění, simulace | Hry v prohlížeči, mobil | FPS prohlížeč, VoIP |
WebTransport: Budoucnost?
Webová doprava a nový standard založený na HTTP/3 (QUIC), který slibuje kombinaci to nejlepší ze všech světů: multiplexované obousměrné toky, spolehlivé a nespolehlivé režimy, žádné blokování head-of-line a nativní přístup prohlížeče. V roce 2026 je podpora prohlížeče maturing (Chrome a Edge to podporují), ale podpora na straně serveru je stále omezená. A protokol pro sledování nové generace her založených na prohlížeči.
5.5 Hybridní vzor: Vícekanálový
Moderní herní backendy zřídka používají pouze jeden protokol. Nejběžnějším vzorem je vícekanálový: Různé kanály pro různé typy dat.
Canale Unreliable (UDP / WebRTC unreliable):
- Posizioni dei giocatori (ogni tick)
- Rotazioni e animazioni
- Effetti particellari
- Dati audio posizionale
Canale Reliable (TCP / WebSocket / WebRTC reliable):
- Danno inflitto/subito
- Cambio arma/inventario
- Chat
- Eventi di gioco (kill, obiettivo)
- Transazioni economiche
- Comandi di matchmaking
6. Serializace zpráv: Každý bajt se počítá
Když odešlete 64 aktualizací za sekundu 100 hráčům, odešle se každý bajt navíc násobit 6400krát za sekundu. Vliv má volba formátu serializace přímo na šířku pásma, latenci a náklady na infrastrukturu.
Porovnání formátů serializace
| Formát | Typ | Velikost (relativní) | Rychlost kódování | Rychlost dekódování | Systém |
|---|---|---|---|---|---|
| JSON | Text | 100 % (základní hodnota) | Pomalý | Pomalý | No |
| MessagePack | Skladby | ~60–70 % | Rychle | Rychle | No |
| Protokolové vyrovnávací paměti | Skladby | ~30–40 % | Velmi rychle | Velmi rychle | Ano (.proto) |
| FlatBuffery | Skladby | ~35–45 % | Nulová kopie | Nulová kopie | Ano (.fbs) |
| Cap'n Proto | Skladby | ~35–45 % | Nulová kopie | Nulová kopie | Si |
// === JSON: ~180 bytes ===
const jsonMsg = JSON.stringify({
type: "player_state",
playerId: "p_abc123",
posX: 123.456,
posY: 78.901,
posZ: 45.678,
rotYaw: 180.5,
rotPitch: -12.3,
health: 85,
weapon: "rifle",
tick: 15042,
});
// === Protocol Buffers: ~42 bytes ===
// Definizione .proto:
// message PlayerState {
// uint32 player_id = 1;
// float pos_x = 2;
// float pos_y = 3;
// float pos_z = 4;
// float rot_yaw = 5;
// float rot_pitch = 6;
// uint32 health = 7;
// WeaponType weapon = 8;
// uint32 tick = 9;
// }
// Risparmio: ~77% meno bandwidth
// A 64 tick/s, 100 giocatori:
// JSON: 180 * 100 * 64 = 1.15 MB/s
// Protobuf: 42 * 100 * 64 = 0.27 MB/s
// Risparmio: 0.88 MB/s = 76% in meno
Kdy použít co
- JSON: Prototypování, turn-by-turn hry, komunikace s externími webovými službami. Snadno laditelné, univerzální
- MessagePack: "Binární JSON" - když chcete zmenšit velikost bez změny logiky kódu. Drop-in náhrada za JSON
- Protokolové vyrovnávací paměti: De facto standard pro vysoce výkonné herní servery. Typované schéma, vícejazyčný codegen, zpětná kompatibilita
- FlatBuffery: Když i náklady na deserializaci jsou příliš vysoké. Přístup s nulovou kopií: Čtení polí přímo z vyrovnávací paměti bez alokace paměti
7. Správa připojení: Sessions, Heartbeat, Reconnection
Ve hře pro více hráčů není síťové připojení nikdy 100% spolehlivé. Hráči ano odpojení z důvodu nestabilní WiFi, změny sítě (4G/WiFi), selhání klienta nebo jednoduše protože hru uzavírají. Robustní herní backend to vše musí zvládnout transparentně.
7.1 Životní cyklus relace
[Client avvia connessione]
|
v
[Handshake + Autenticazione] -- Token JWT o session ticket
|
v
[Session creata sul server] -- SessionID, PlayerID, Timestamp
|
v
[Heartbeat loop avviato] -- Ping ogni 1-5 secondi
|
v
[Gioco attivo] -- Input/State loop
|
v
[Disconnessione rilevata] -- Timeout heartbeat (10-30s)
|
+--- [Reconnection window] -- 30-120s per riconnettersi
| |
| +--> Riconnesso: ripristina sessione, invia stato corrente
| |
| +--> Timeout: sessione distrutta, giocatore rimosso
|
v
[Sessione terminata] -- Salva statistiche, libera risorse
7.2 Detekce srdečního tepu a odpojení
Il tlukot srdce a pravidelnou zprávu, kterou klient posílá na server (nebo naopak) pro označení, že připojení je aktivní. Pokud server po určitou dobu neobdrží prezenční signály konfigurovatelné, považuje klienta za odpojeného. Tep také slouží k měření latence (RTT) e il nervozita.
interface ConnectionMetrics {
readonly lastHeartbeat: number;
readonly rttMs: number;
readonly jitterMs: number;
readonly packetLoss: number;
readonly rttHistory: ReadonlyArray<number>;
}
class ConnectionManager {
private readonly HEARTBEAT_INTERVAL = 2000; // 2 secondi
private readonly DISCONNECT_TIMEOUT = 15000; // 15 secondi
private readonly RECONNECT_WINDOW = 60000; // 60 secondi
private readonly sessions: Map<string, SessionData> = new Map();
handleHeartbeat(sessionId: string, clientTimestamp: number): void {
const session = this.sessions.get(sessionId);
if (!session) return;
const now = Date.now();
const rtt = now - clientTimestamp;
// Calcola jitter (variazione del RTT)
const prevRtt = session.metrics.rttMs;
const jitter = Math.abs(rtt - prevRtt);
// Crea nuovo oggetto metrics (immutabile)
const updatedMetrics: ConnectionMetrics = {
lastHeartbeat: now,
rttMs: rtt,
jitterMs: jitter,
packetLoss: session.metrics.packetLoss,
rttHistory: [...session.metrics.rttHistory.slice(-19), rtt],
};
// Aggiorna sessione con nuove metriche
this.sessions.set(sessionId, {
...session,
metrics: updatedMetrics,
});
}
checkDisconnections(): void {
const now = Date.now();
for (const [sessionId, session] of this.sessions) {
const elapsed = now - session.metrics.lastHeartbeat;
if (elapsed > this.DISCONNECT_TIMEOUT && session.status === 'connected') {
// Passa a stato "disconnesso" ma mantiene la sessione
this.sessions.set(sessionId, {
...session,
status: 'disconnected',
disconnectedAt: now,
});
console.log(`Player ${session.playerId} disconnesso. Reconnect window: 60s`);
}
if (session.status === 'disconnected') {
const disconnectElapsed = now - (session.disconnectedAt ?? now);
if (disconnectElapsed > this.RECONNECT_WINDOW) {
// Finestra di reconnection scaduta
this.destroySession(sessionId);
}
}
}
}
handleReconnect(playerId: string, newSocket: WebSocket): boolean {
// Cerca sessione disconnessa per questo player
for (const [sessionId, session] of this.sessions) {
if (session.playerId === playerId && session.status === 'disconnected') {
// Ripristina la sessione con la nuova connessione
this.sessions.set(sessionId, {
...session,
status: 'connected',
socket: newSocket,
metrics: { ...session.metrics, lastHeartbeat: Date.now() },
});
// Invia lo stato corrente del gioco al client riconnesso
this.sendFullStateSync(sessionId);
return true;
}
}
return false;
}
private destroySession(sessionId: string): void {
const session = this.sessions.get(sessionId);
if (session) {
console.log(`Sessione ${sessionId} distrutta per player ${session.playerId}`);
this.sessions.delete(sessionId);
}
}
}
8. Databáze: The Persistence Stack
Herní backend nepoužívá pouze jednu databázi: používá jednu stoh skladovacích motorů, každý je optimalizován pro konkrétní typ dat a přístupový vzor.
Databáze zásobníku pro herní backend
| Vrstvy | Technologie | Co ukládá | Latence |
|---|---|---|---|
| L1 - V paměti | Datové struktury v RAM | Stav rámce, vstupní vyrovnávací paměť | < 0,001 ms |
| L2 - Distribuovaná mezipaměť | Redis/Vážka | Stav relace, žebříček, fronta dohazování | 0,1-1 ms |
| L3 - Relační databáze | PostgreSQL / CockroachDB | Profily hráčů, inventář, nákupy, hodnocení | 1-10 ms |
| L4 - Časová řada | TimescaleDB / InfluxDB | Telemetrie, metriky výkonu, analytika | 1-5 ms |
| L5 - Skladování objektů | S3 / GCS | Přehrání, snímky obrazovky, aktiva, zálohy | 50-200 ms |
8.1 Redis pro stav v reálném čase
Redis je nejdůležitější součástí databázového zásobníku hry. Jeho struktury nativní data (seřazené sady, hash, seznamy, pub/sub) se mapují přímo do herních vzorů:
- Seřazené sady pro žebříček a hodnocení (ZADD, ZRANK, ZRANGE)
- Hashe pro stav relace (HSET, HGETALL)
- Seznamy pro dohazovací fronty (LPUSH, RPOP)
- Pub/Sub pro komunikaci mezi herními servery a službami
- Proudy pro získávání událostí a protokoly auditu
8.2 PostgreSQL pro perzistenci
Pro všechna data, která musí přežít restart serveru: profily hráčů, postup,
zásoby, ekonomické transakce, historie šarží. PostgreSQL nabízí transakce ACID,
JSON(B) pro polostrukturovaná data as rozšířeními jako pgvector podporuje
také hledání podobnosti pro dohazování založené na dovednostech.
9. Infrastruktura: Dedikované servery, kontejnery, organizace
Na rozdíl od bezstavových webových serverů, které se škálují přidáváním replik za nástroj pro vyrovnávání zatížení, herní servery jsou stavový: každá instance spravuje jednu nebo více aktivních her se stavem v paměti. Díky tomu je škálování a orchestrace mnohem složitější.
9.1 Dedikované herní servery
Un vyhrazený herní server a proces, který provozuje simulaci singlu hru (nebo oblast herního světa). Na rozdíl od „serverů pro naslouchání“ (kde hráč funguje také jako server), dedikovaný server běží na vyhrazeném hardwaru v cloudu, což zaručuje konzistentní výkon a férovost.
[Internet]
|
[CDN / Edge]
|
[Load Balancer (L7)]
/ \
[Gateway API] [Gateway API]
| |
+--------+--------+-------+--------+
| | | | |
[Matchmaker] [Auth] [Social] [Shop] [Leaderboard]
| |
v v
[Fleet Manager / Orchestrator] [Redis Cluster]
| |
+---+---+---+---+ |
| | | | | |
[GS] [GS] [GS] [GS] [GS] <---> [PostgreSQL]
Game Server Instances
Legenda:
GS = Game Server (una partita ciascuno)
Ogni GS e un container/pod con CPU e RAM dedicate
Il Fleet Manager scala il numero di GS in base alla domanda
9.2 Kontejnerizace pomocí Dockeru
Každý herní server běží v kontejneru Docker, což zajišťuje izolaci, reprodukovatelnost a nasazení rychle. Kontejner obsahuje binární soubor serveru, konfigurace a závislosti. Lehkost kontejnerů umožňuje spouštět nové instance během několika sekund.
9.3 Orchestrace s Kubernetes a Agones
agones a open-source projekt od Google, který rozšiřuje Kubernetes o správu vyhrazené herní servery. Poskytuje vlastní definice zdrojů (CRD) pro definování herního serveru, Fleet a FleetAutoscaler. Správce vozového parku monitoruje poptávku po dávkách a automaticky měří počet dostupných serverů.
Srovnání orchestračních platforem
| Platforma | Typ | Mrak | Silné stránky |
|---|---|---|---|
| agones | Open source (K8s) | Jakékoli + on-premise | Naprostá flexibilita, žádné uzamčení dodavatele |
| Amazon GameLift | Spravováno (AWS) | AWS | Integrace AWS, dohazování FlexMatch |
| Azure PlayFab | Spravováno (Azure) | Blankyt | Kompletní ekosystém (LiveOps, analytika, ekonomika) |
| herní servery Google Cloud | Spravováno (GCP) | GCP | Využívá Agones, globální škálování |
10. Vzor škálování: Lobby, Svět, Zóna
Ne všechny hry mají stejný rozsah. Vzor měřítka závisí na pohlaví a herní struktura. Zde jsou tři hlavní vzory.
10.1 Lobby/match server
Používá FPS, Battle Royale, MOBA. Každá hra je izolovaná instance s číslem pevný počet hráčů (10-100). Na konci zápasu je server zničen a zdroje recyklovaný. Škálování = zvýšení počtu instancí.
10.2 Světový server (trvalý svět)
Používané MMO. Svět vytrvalý a rozdělený na oblasti, každý zvládl z dedikovaného serveru. Hráči se mezi zónami pohybují transparentním handoffem. Zónové servery spolu komunikují za účelem správy hranic.
10.3 Instanční zóny
Hybrid: svět je perzistentní, ale přicházejí specifické oblasti (dungeony, raidy, arény). vytvořená instance dynamicky. Každá skupina hráčů obdrží vlastní kopii oblasti. To vám umožní škálovat oblasti s vysokou hustotou bez přetížení světový server.
LOBBY/MATCH SERVER (FPS, BR):
[Matchmaker] --> [Server Pool]
|
+---------+---------+
| | |
[Match 1] [Match 2] [Match 3]
10 players 10 players 10 players
(30 min) (25 min) (nuovo)
WORLD SERVER (MMO):
[World Manager]
|
+---+---+---+---+
| | | | |
[Zona A][Zona B][Zona C][Zona D]
Citta Foresta Dungeon PvP
200 p. 50 p. 30 p. 80 p.
^ ^
|--- Handoff zone ---|
INSTANCED ZONES (MMO + Dungeon):
[Zona Citta] --> [Ingresso Dungeon]
|
+---------+---------+
| | |
[Dungeon [Dungeon [Dungeon
Copia 1] Copia 2] Copia 3]
5 players 5 players 5 players
11. Backend-as-a-Service pro Game: The Platforms
Ne každý musí (nebo chce) stavět herní backend od nuly. Existují platformy Backend-as-a-Service (BaaS) nabízející komponenty připravené k použití: matchmaking, leaderboard, ověřování, ukládání, ekonomika ve hře. Výběr závisí na rozpočtu, kontrole požadované a herní žánr.
Porovnání herních platforem BaaS
| Platforma | Jazyk serveru | Open Source | Samoobslužný | Silné stránky | Ideální pro |
|---|---|---|---|---|---|
| Nakama | Běž, TS, Lua | Si | Si | Real-time, dohazování, ukládání | Nezávislé, střední, mobilní |
| Colyseus | TypeScript | Si | Si | Autoritativní, automatická synchronizace stavu | Prohlížečové hry, prototypy |
| PlayFab | C# (Azure Functions) | No | No | LiveOps, ekonomika, analytika | AAA, mobilní F2P |
| Amazon GameLift | C++, C# | No | No | Správa vozového parku, FlexMatch | AAA multiplayer |
| Foton | C# | No | Částečný | Integrace jednoty, relé | Hry Unity, mobil |
| Zrcadlo | C# | Si | Si | Unity networking, náhrada HLAPI | Nezávislé hry Unity |
Sestavení vs nákup: Kritéria výběru
- Použijte BaaS pokud: omezený rozpočet, priorita time-to-market, standardní žánr (casual, puzzle, karetní hra), malý tým
- Sestavit na míru se: extrémní požadavky na latenci (<20 ms), jedinečná herní logika, potřeba naprosté kontroly nad síťovým kódem a anti-cheat, měřítko >100K CCU
- Hybridní přístup: použijte BaaS pro ověřování, žebříček a sociální sítě, ale vytvořte vlastní herní server pro herní logiku
12. Metriky výkonu: Co sledovat
Backend hry bez pozorovatelnosti a časovaná bomba. Toto jsou metriky základy, které musí každý tým sledovat ve výrobě.
Klíčové metriky backendu hry
| Metrický | Popis | Cíl | Poplach |
|---|---|---|---|
| CCU | Souběžní připojení uživatelé | Záleží na žánru | > 90% kapacity |
| Trvání zaškrtnutí (str. 99) | Zaškrtněte čas zpracování | < 80 % tikového rozpočtu | > 90 % rozpočtu |
| RTT (p50 / p95 / p99) | Zpáteční čas klient-server | p50 < 50 ms, p99 < 150 ms | p99 > 200 ms |
| Ztráta paketů | Procento ztracených paketů | < 1 % | > 3 % |
| Jitter | Variace latence | < 10 ms | > 30 ms |
| Zprávy/sec | Zprávy zpracované za sekundu na server | > 10 000 msg/s | < 5 000 zpráv/s |
| Šířka pásma na hráče | Výstup kB/s na hráče | 5-30 kB/s | > 50 kB/s |
| Rychlost opětovného připojení | Procento úspěšných obnovení připojení | > 90 % | < 70 % |
| Čas spuštění serveru | Je čas spustit novou instanci | < 10 s | > 30s |
// Struttura per le metriche di un game server in Go
type TickMetrics struct {
TickNumber uint64
Duration time.Duration
PlayersActive int
InputsProcessed int
MessagesOut int
BytesOut int64
}
type ServerMetrics struct {
mu sync.RWMutex
tickDurations []time.Duration // ring buffer ultimi 1000 tick
totalTicks uint64
overrunCount uint64
ccu int32
}
func (m *ServerMetrics) RecordTick(metrics TickMetrics) {
m.mu.Lock()
defer m.mu.Unlock()
idx := m.totalTicks % 1000
m.tickDurations[idx] = metrics.Duration
m.totalTicks++
if metrics.Duration > tickBudget {
m.overrunCount++
log.Printf(
"TICK OVERRUN #%d: tick=%d duration=%v budget=%v players=%d",
m.overrunCount,
metrics.TickNumber,
metrics.Duration,
tickBudget,
metrics.PlayersActive,
)
}
}
// Calcola il percentile p99 della durata dei tick
func (m *ServerMetrics) P99TickDuration() time.Duration {
m.mu.RLock()
defer m.mu.RUnlock()
sorted := make([]time.Duration, len(m.tickDurations))
copy(sorted, m.tickDurations)
sort.Slice(sorted, func(i, j int) bool {
return sorted[i] < sorted[j]
})
idx := int(float64(len(sorted)) * 0.99)
return sorted[idx]
}
13. Dát to všechno dohromady: Kompletní architektura
Zde je přehled všech součástí backendu moderní hry pro více hráčů a jak vzájemně se ovlivňují.
+==============================================================+
| CLIENT LAYER |
+==============================================================+
| [Game Client] [Game Client] [Game Client] [Game Client] |
| | | | | |
| WebSocket/UDP WebSocket/UDP WebSocket/UDP WebSocket/UDP |
+======|==============|==============|==============|==========+
| | | |
+======|==============|==============|==============|==========+
| EDGE LAYER |
+==============================================================+
| [CDN] [DDoS Protection] [Load Balancer] [SSL Termination]|
+==========================|===================================+
|
+==========================|===================================+
| GATEWAY LAYER |
+==============================================================+
| [API Gateway] [WebSocket Gateway] |
| REST per login, Routing verso il game server |
| shop, profili corretto per la partita |
+=========|========================|===========================+
| |
+---------+----------+ +--------+--------+
| SERVICE LAYER | | GAME SERVER |
+====================+ | LAYER |
| [Auth Service] | +=================+
| [Matchmaker] | | [GS Instance 1] |
| [Leaderboard] | | [GS Instance 2] |
| [Shop/Economy] | | [GS Instance 3] |
| [Social/Chat] | | [GS Instance N] |
| [Analytics] | +=================+
+========|===========+ |
| |
+========|======================|===========================+
| DATA LAYER |
+============================================================+
| [Redis] [PostgreSQL] [TimescaleDB] [S3/GCS] |
| Sessions, Profili, Telemetria, Replay, |
| Leaderboard, Inventario, Metriche, Assets, |
| Match Queue Transazioni Analytics Backup |
+============================================================+
| |
| [Agones / GameLift] - Fleet Management & Autoscaling |
| [Prometheus + Grafana] - Monitoring & Alerting |
| [ELK / Loki] - Logging centralizzato |
+============================================================+
Další kroky
V tomto článku jste získali úplné porozumění anatomii herního backendu multiplayer: od síťové architektury po transportní protokoly, od autoritativní herní smyčky po serializaci zpráv, od správy připojení po vzory škálování. Viděli jste, jak jednotlivé komponenty interagují s ostatními a jaké jsou architektonické kompromisy průvodce výběrem designu.
Nel další článek dostaneme se do srdce síťového kódu pro více hráčů: the synchronizace stavu. Klientskou stranu prozkoumáme do hloubky predikce, odsouhlasení serveru, interpolace, kompenzace zpoždění a vrácení zpět síťový kód. Uvidíme, jak moderní hry vytvoří iluzi plynulého zážitku navzdory latence sítě.
Další zdroje
- Gabriel Gambetta: "Rychlý multiplayer" - Série referenčních článků o architektuře klient-server pro hry
- Valve Developer Wiki: "Source Multiplayer Networking" - Technická dokumentace k síťovému kódu Source Engine
- Glenn Fiedler: "Game Networking" - Kompletní série o protokolech, synchronizaci stavu a zabezpečení
- Dokumentace agones: Kompletní průvodce orchestrací herních serverů na Kubernetes
- Colyseus.io: Open source framework pro herní server Node.js s automatickou synchronizací stavu
- Nakama od Heroic Labs: Herní server s otevřeným zdrojovým kódem s matchmakingem, úložištěm a multiplayerem v reálném čase







