METABYTE
Inapoi la articole

Multiplayer Game Server Architecture: Authoritative vs Peer-to-Peer

Cum alegi intre server authoritative si peer-to-peer pentru jocul tau. Arhitecturi, stackuri, costuri, capcane in productie si cand are sens un model hibrid.

14 mai 202615 min de cititAI-research draft
Multiplayer Game Server Architecture: Authoritative vs Peer-to-Peer

Daca alegi modelul de retea gresit, vei plati dublu: costuri de hosting care explodeaza sau luni de anti-cheat pompate intr-o arhitectura imposibil de aparat. Decizia authoritative vs peer-to-peer nu e filosofie — e una care se vede in ping, in churn si in buget.

Pe scurt: jocurile competitive, cu economie server-side si risc de cheat, merg pe server authoritative. Jocurile co-op casual, fightere cu 2–4 jucatori sau RTS determinist merg bine pe P2P cu rollback/lockstep. In continuare intram in arhitecturi concrete, trade-off-uri reale, costuri si pitfall-uri de productie.

Modelele principale: authoritative si peer-to-peer

Exista trei familii practice de modele:

  • Server authoritative: clientii trimit input, serverul simuleaza adevarul, trimite snapshot-uri, aplica anti-cheat si persistenta. Folosit in shootere, battle royale, MMO, survival cu economie.
  • Peer-to-peer (P2P) determinist: toti clientii ruleaza aceeasi simulare determinista (RTS-uri clasice). Comunica doar inputuri in lockstep. Sensibil la desync si la comenzi deterministe stricte.
  • P2P cu rollback netcode: folosit in fightere/arcade 1v1–1v4. Clientii prezic local, sincronizeaza inputurile pe cadre si re-executa un buffer de stari cand sosesc inputuri intarziate. Latenta perceputa scade mult.

Mai exista si hibridul host-authoritative (un jucator e „serverul”), bun pentru co-op mic, dar cu riscuri de cheat si stabilitate la host migration.

Cand alegi ce: situatii tipice

  • FPS/TPS competitiv (ranked, esports): server authoritative cu tick 30–60 Hz, lag compensation pe lovituri, anti-cheat, matchmaking regional. P2P aici e aproape intotdeauna o idee proasta.
  • Fighter 1v1: P2P cu rollback (GGPO-like), target 120 Hz sim intern, frame delay configurabil. Autoritative doar pentru rating/economie.
  • RTS determinist: P2P lockstep cu input-delay mic si verificare de desync (hash al starii). Server optional pentru lobby si replays.
  • Co-op casual (4–8 jucatori), survival PVE: host-authoritative sau P2P cu migrare de host; daca ai economie/persistenta serioasa (tranzactii, monetizare), muta-le server-side.
  • Jocuri browser/Telegram Mini Apps cu minigame realtime: WebRTC datachannels P2P cu un relay fallback; authoritative doar pentru anti-cheat minim si scoruri.

Regula pragmatica: daca integritatea competitiva si marketplace-ul conteaza, authoritative. Daca ritmul e local, mic grup si vrei cost zero la servere, P2P/host.

Arhitectura server authoritative, pe concret

Flux de date si componente

  • Client trimite input (comenzi cu secventa si timestamp) prin UDP/QUIC sau WebSocket.
  • Serverul ruleaza simularea pe tick fix (de ex. 60 Hz), aplica input-urile in ordinea corecta, simuleaza fizica, lovituri si gameplay authoritative.
  • Serverul emite state deltas/snapshots catre clienti, cu compresie si relevanta per jucator (area-of-interest).
  • Clientul face client-side prediction si reconciliation pe baza lastAckInput primit de la server; interpoleaza alte entitati pentru net-smoothing.
  • Persistenta: serverul scrie in Postgres (inventar, progres), foloseste Redis pentru matchmaking/session dir si coada de mesaje. Telemetrie in Prometheus + Grafana. Rate limiting si DDoS scrubbing la edge (Cloudflare Magic Transit/Spectrum pentru UDP, sau un ELB/NLB cu GameLift/Agones pentru TCP/QUIC).

Stackuri tipice:

  • Unreal Engine 5 Dedicated Server + Epic Online Services (matchmaking, lobbies), sau AWS GameLift/Agones pentru orchestrare.
  • Unity headless + Netcode for GameObjects/Netcode for Entities (ECS) cu Photon/Fish-Networking sau Relay propriu.
  • Node.js/TypeScript cu Colyseus pentru jocuri 2D/party; Go/C++ custom pentru performanta maxima; Nakama (Go + Postgres + Redis) pentru backend social/persistenta.
  • Transport: ENet/RakNet (UDP cu fiabilitate optionala), QUIC (HTTP/3), Steam Networking Sockets pentru ecosistem Steam, WebRTC pentru browser/mobile cu NAT traversal (STUN/TURN).

Ciclu de server si reconciliere

Un server authoritative minimalist in TypeScript cu WebSocket (demonstrativ pentru prototipuri):

import WebSocket, { WebSocketServer } from 'ws';

type Input = { seq: number; dt: number; ax: number; ay: number; fire: boolean; ts: number };

type Player = { id: string; x: number; y: number; vx: number; vy: number; lastAck: number };

const TICK = 1000 / 60; // 60 Hz
const players = new Map<string, Player>();
const inputQueue = new Map<string, Input[]>();

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  const id = crypto.randomUUID();
  players.set(id, { id, x: 0, y: 0, vx: 0, vy: 0, lastAck: 0 });
  inputQueue.set(id, []);

  ws.on('message', (buf) => {
    const msg = JSON.parse(buf.toString());
    if (msg.t === 'inp') {
      // sanitize input
      const i: Input = {
        seq: Math.min(msg.seq ?? 0, 1e9),
        dt: Math.min(Math.max(msg.dt ?? 16, 1), 50),
        ax: Math.max(Math.min(msg.ax ?? 0, 1), -1),
        ay: Math.max(Math.min(msg.ay ?? 0, 1), -1),
        fire: !!msg.fire,
        ts: Date.now()
      };
      inputQueue.get(id)!.push(i);
    }
  });

  ws.on('close', () => {
    players.delete(id);
    inputQueue.delete(id);
  });
});

function simPlayer(p: Player, inp: Input) {
  const accel = 20; // units/s^2
  p.vx += inp.ax * accel * (inp.dt / 1000);
  p.vy += inp.ay * accel * (inp.dt / 1000);
  // clamp speed
  const maxV = 6;
  const sp = Math.hypot(p.vx, p.vy);
  if (sp > maxV) { p.vx *= maxV / sp; p.vy *= maxV / sp; }
  p.x += p.vx * (inp.dt / 1000);
  p.y += p.vy * (inp.dt / 1000);
}

setInterval(() => {
  // apply inputs per player, in order
  for (const [id, p] of players) {
    const q = inputQueue.get(id)!;
    q.sort((a, b) => a.seq - b.seq);
    for (const inp of q.splice(0, q.length)) {
      // anti-cheat minimal: drop old/too-fast inputs
      if (Date.now() - inp.ts > 500) continue;
      simPlayer(p, inp);
      p.lastAck = inp.seq;
    }
  }

  // broadcast snapshot deltas
  const state = [] as any[];
  for (const p of players.values()) state.push({ id: p.id, x: p.x, y: p.y, vx: p.vx, vy: p.vy });
  const msg = JSON.stringify({ t: 'snap', tsv: Date.now(), state });

  for (const client of wss.clients) {
    if (client.readyState === WebSocket.OPEN) client.send(msg);
  }
}, TICK);

Acesta este un schelet pentru prototip, nu productie. In productie adaugi: delta-compression (zstd), relevanta per jucator, lag compensation (reconstruiesti scenele la ts - RTT pentru hit-scan), limitari pe input rate si verificari de fisica anti-cheat pe server.

Lag compensation si anti-cheat

  • Lag compensation: stochezi un istoric de pozitii pe ~200 ms; cand primesti un fire cu timestamp client, faci raycast in starea istorica. Eviti „leading” nedrept pe ping mare.
  • Anti-cheat: semnatura client secure boot (EAC/BattleEye pentru PC), sanity checks pe server (viteze maxime, rate fire), verificari ale proiectilelor pe server, server nu accepta stari impuse de client. Pentru economie/inventory, scrierea e numai de pe server in DB.

Orchestrare si observabilitate

  • Orchestrare: Agones pe Kubernetes pentru alocare dinamica de game servers; sau GameLift pentru AWS-first; scaling pe Ready/Allocated si pe p95 CPU si memorie.
  • Observabilitate: Prometheus (tick time, p50/p95 latenta end-to-end, packet loss), Grafana dashboards, logs structurate in Loki/ELK, sampling la profiluri CPU. Alarme pe crestere packet loss > 5% intr-o regiune.

Arhitectura P2P moderna: lockstep si rollback

P2P determinist (RTS)

  • Toata simularea e determinista (fara floating nondeterminist, fara RNG necontrolat). Input-urile tuturor jucatorilor pentru „frame N” se colecteaza, apoi se avanseaza „in lockstep”.
  • Daca un input lipseste, se asteapta un mic delay (input delay) sau se dropeaza jucatorul.
  • Detectia desync: fiecare peer calculeaza un hash al starii la frame-uri cheie si le compara. Daca diverge, se opreste si se face resync/replay.

Instrumente: Steam Networking Sockets pentru transport P2P, EOS P2P, WebRTC datachannels (STUN/TURN). Pentru hashing: xxHash/CityHash pe bufere deterministe.

P2P cu rollback (fightere)

  • Fiecare peer prezice inputurile lipsa pe cateva cadre, randeaza imediat, iar cand inputul real soseste, re-executa dintr-un buffer de stari (rollback window 6–10 frame-uri tipic).
  • Cheia e performanta simularii per frame si memorie pentru state snapshot-uri. Eviti obiecte alocate masiv (GC spikes). ECS sau data-oriented ajuta.
  • Host election si NAT traversal: STUN pentru descoperire, TURN/relays numai cand nu exista direct path (costa egress). Steam/EOS ofera relays proprietare.

Avantaje P2P: cost aproape zero pe server (in afara de relays/matchmaking), latenta „simtita” mai mica la rollback, uptime independent de cloud. Dezavantaje: risc de cheat (man-in-the-middle, mem-edit), complexitate pentru determinism si desync handling, NAT si firewall.

Tabel comparativ al compromisurilor

CriteriuServer authoritativeP2P (lockstep/rollback)
Integritate anti-cheatFoarte buna (server decide)Slaba-medie (host/peers pot trișa)
Complexitate implementareMedie-ridicata (server + client)Ridicata (determinism/rollback)
Cost OPEXMediu-ridicat (compute + egress)Redus (doar relays si servicii auxiliare)
Latenta perceputaBuna cu prediction/compensationExcelenta la rollback, proasta la lockstep
Scalare la mii de CCULiniara cu orchestrareAproape gratuita la transport, greu la NAT
Persistenta/economieNaturala pe serverNecesita un server auxiliar
Cross-play si mobileSimplu cu server relayPosibile probleme NAT/OS
Rezilienta DDoSMai buna cu edge scrubbingPeer IP expus, dificil

Nimic nu e „magie”: daca vrei cost mic, vei plati in complexitate sau in risc de cheat. Daca vrei integritate, platesti servere si operare. Ingineria e, uneori, despre care factura preferi sa o platesti.

Ce se strica in productie

  • Tick drift si GC: la Node/Java/C# poti avea stop-the-world care rupe tick-ul de 60 Hz. Rezolvi cu profiling, pool-uri de obiecte, ECS/data-oriented, sau limbaje cu GC predictibil/arena alloc (C++/Rust/Go cu grija).
  • Packet loss si reorder (UDP): implementeaza sequence numbers, ack/NAK, si retransmisie selectiva pe canale fiabile. Pentru lovituri: trimite doar evenimente, nu stari masive.
  • NAT traversal: simetrice NAT blocheaza P2P; pregateste TURN/relays si rate-limiting. Pe mobile, comutarea Wi-Fi/5G pierde conexiunea — reconectare la sesiune si resync rapid.
  • DDoS si scraping IP: ascunde IP-urile serverelor in authoritative (proxies/anycast). In P2P, IP-urile peerilor pot fi expuse; foloseste relays in regiuni sensibile.
  • Migrare de host: in host-authoritative, cand host-ul iese, migrezi statul la alt peer. Testeaza intens — pierderi de pachete in timpul migrarii = desync si rage quit.
  • Clock drift: pentru lag compensation si anti-cheat, sincronizeaza ceasurile (NTP, Steam clock). Nu te baza pe Date.now() din client pentru adevar absolut.
  • Persistenta lenesa: scrieri mari la final de meci pot bloca DB; fa write-through incremental si batch-uri. Optimizarea ordonarii in DB conteaza; vezi bune practici de indecsi si sortari in evolutia ORDER BY.
  • Edge si patching: update-uri gresite la proxy pot rupe WebSocket/UDP (reguli MTU, Path MTU Discovery). Monitorizeaza erorile 4xx/5xx la edge; cand folosesti Nginx/Envoy, ramane valabil principiul „nu atinge in vineri seara” — a fost scris cu sange de SRE.

Cost si ROI: cum bugetezi corect

Nu exista pret unic, dar poti face o planificare „ordine de marime”.

Compute si densitate de sesiuni

  • Un server authoritative CPU-bound de shooter la 60 Hz poate sustine 60–100 jucatori pe 4 vCPU daca sim-ul e eficient. Un match 10v10 pe 2 vCPU este realist pentru jocuri 3D moderate. Jocurile 2D/party pot atinge 200–500 jucatori/4 vCPU.
  • Densitate creste daca faci area-of-interest si trunchiere de fizica. Scade daca ai proiectile balistice si destructibilitate.

Exemplu aproximativ: o instanta 8 vCPU (cloud general-purpose) la ~0.30 USD/ora poate rula 3–6 meciuri de 20 jucatori. La 1000 CCU medii, ai nevoie de 10–20 astfel de instante, deci ~72–144 USD/zi compute. Egress poate dubla costul.

Latime de banda si egress

  • Snapshot/delta eficient: 20–80 kbps per client downlink in jocuri action; uplink 10–30 kbps per client. Egress public cloud costa; pe AWS/GCP poti vedea cateva sute USD/luna doar din traficul jocului la cateva mii CCU.
  • P2P reduce egress server, dar relays TURN au cost mare cand intra in joc (transferul trece prin serverul tau oricum).

Servicii gestionate vs self-host

  • GameLift/Multiplay/Photon Fusion reduc time-to-market, dar vei plati un premium per ora/conn. Bun pentru lansare/alpha; apoi poti trece la Agones self-host daca ai volum si echipa de SRE.
  • Nakama (self-host) ofera matchmaking, prieteni, leaderboards; economisesti timp pe backend social.

Costul anti-cheat si QA

  • Anti-cheat comercial (EAC/Battleye) are licentiere si integrare; dar te scuteste de luni de munca si reputatie stricata. In authoritative, tot ai nevoie de server-side sanity checks.
  • QA netcode: setup lab cu retea emulata (tc/netem, Clumsy), scenarii cu 1–20% packet loss, jitter 10–100 ms, 3–5 dispozitive mobile reale per platforma. E mai ieftin sa simulezi acum decat sa-ti invete jucatorii termenii „teleport” si „desync”.

ROI pragmatic: authoritative creste retentia cand conteaza corectitudinea; P2P creste retentia cand conteaza latenta scazuta si zero friction. Alege dupa bucla ta de joc si modelul de monetizare.

Modele hibride si exceptii utile

  • Hibrid „server pentru economie, P2P pentru moment-to-moment”: serverul valideaza tranzactii, progres, crafting; combat-ul local e P2P/rollback. Bun la co-op survival.
  • Host-authoritative cu validare server-side pe evenimente critice (loot, boss kill). Daca pica host-ul, faci upload incremental de state pe un relay, pentru migrari rapide.
  • Determinist P2P cu „arbiter server”: in caz de conflict/cheat detection, serverul arbitreaza si poate penaliza. Ajuta la ranked si leaderboarduri curate.

Stackuri recomandate pe tipuri de joc

  • Shooter/BR competitiv: UE5 Dedicated Server + EOS (lobbies, auth) + Agones sau GameLift; transport ENet/Steam Sockets; Redis pentru matchmaking, Postgres pentru economie; Cloudflare Spectrum pentru UDP; Prometheus/Grafana/Loki pentru observabilitate.
  • Co-op Unity 3D: Unity headless + Netcode for GameObjects, Relay (Photon/Crossplay Relay) + Host migration; economie pe server mic Node/Go + Postgres.
  • Party 2D/Web: Colyseus (Node/TS) + WebSocket/WebRTC DataChannels; autoscaling pe Kubernetes; persista scoruri in Postgres; foloseste rate limiting la edge. Pentru optimizari de JS runtime, evaluarile despre ecosisteme ca Bun rescris in Rust pot inspira decizii de toolchain, dar nu inlocuiesc profilarea.
  • RTS determinist: motor custom/Unity DOTS cu fixed-point math, P2P lockstep peste Steam/EOS; server subtire pentru lobby, replays, anti-abuz minimal.
  • Fighter 1v1: GGPO-like rollback, P2P peste Steam/EOS/WebRTC; relay fallback; ranking si matchmaking pe backend Nakama/Go, verificari anti-boosting.

Pipeline de livrare

  • Teste determinism: rulare dubla a aceluiasi demo, verificare hash state.
  • Teste retea: scripturi tc pentru latency/loss/jitter; canale CI care ruleaza smoke pe 30/60/120 Hz.
  • Canary rollout pe o singura regiune; daca p95 tick time trece pragul, opreste rollout-ul.

Ce trebuie masurat constant

  • p50/p95/p99 RTT per regiune; packet loss; jitter; p95 tick time; rata de resync/rollback; disconnect rate per platforma; cost egress/CCU; densitate medie jucatori per instanta. Daca nu masori, optimizarile sunt doar opinii ambalate frumos.

Exemple de flux end-to-end (authoritative)

  • Client trimite Move{seq,ax,ay} la 60 Hz; serverul proceseaza pe tick; tine history[200ms] pentru lag compensation; la fiecare 100 ms trimite Delta{entities in AOI}. Clientul reconciliaza pe baza lastAck si interpoleaza alti jucatori pe 100 ms buffer.
  • Pentru lovituri: client trimite Fire{seq,shootTS,dir}; server cauta in istoric pozitia tintei la shootTS - interpOffset, face raycast, decide hit, aplica damage si emite evenimentul.

Ce sa NU faci

  • Sa trimiti de la client pozitii absolute drept „adevar”. Deschizi poarta la speedhack si teleport.
  • Sa legi sim-ul de framerate. Foloseste fixed timestep si integrari corecte (ex.: semi-implicit Euler pentru fizica simpla).
  • Sa depinzi de Date.now() pentru sincronizare. Foloseste tick counters si offset server-time.
  • Sa pui toata logica in RPC-uri synchronous. Foloseste mesaje idempotente si stateless unde se poate.

FAQ

Q: De ce un server authoritative pare „mai laggy” desi e corect? A: Pentru ca serverul valideaza si trunchiaza update-urile; adauga prediction si reconciliation corect pe client. Tuning-ul bufferelor de interpolare si al lag compensation reduce perceputul.

Q: Pot face P2P fara riscuri de cheat? A: Nu complet. Poti reduce cu verificari la host, hash de stare, server arbitru pentru rank, dar cine controleaza clientul controleaza memoria. Pentru competitiv, mergi pe authoritative.

Q: Ce tick rate sa aleg? A: 30 Hz e suficient pentru multe jocuri; 60 Hz pentru shootere rapide; peste 60 Hz are diminishing returns si costa CPU/banda. Mai important e stabilitatea tick-ului si net smoothing.

Q: WebRTC e suficient pentru browser multiplayer? A: Da, pentru 2D/party/co-op si P2P; pentru authoritative in browser, WebSocket e mai simplu si suficient. Daca ai nevoie de UDP-like, WebRTC DataChannels sunt opțiunea.

Q: Cum fac matchmaking corect pe regiuni? A: Harta de regiuni cu latency buckets (0–50, 50–100, 100–150 ms), preferi regiunea comuna minima. Poti permite cross-region ca fallback, dar semnaleaza ping-ul jucatorului.

Q: Pot muta de la P2P la authoritative dupa lansare? A: Este greu. Protocolul, sim-ul si economiile trebuie refactorizate. Daca anticipezi crestere, proiecteaza transportul si serializarea compatibile de la inceput.

Concluzii tactice

  • Alege authoritative pentru competitiv, economie server-side si anti-cheat; P2P/rollback pentru 1v1 si co-op mic cu cost minim.
  • Construieste pe un transport fiabil (ENet/QUIC/Steam Sockets) si separa clar inputurile de stari.
  • Masoara p95 tick si p95 RTT, nu te ghida dupa „merge la mine”.
  • Planifica egress si compresie; delta + AOI reduc factura cloud.
  • Testeaza determinismul/rollback cu tool-uri de retea emulata in CI, nu doar la QA manual.
  • Accepta ca nu exista solutie perfecta — dar exista o solutie potrivita pentru bucla ta de joc si buget.

Daca construiesti un joc multiplayer si ai nevoie de arhitectura, prototip sau audit de retea, scrie-ne: /contact. In calitate de studio care livreaza jocuri si backend-uri, putem proiecta, implementa si opera modelul corect pentru cazul tau.

Key takeaways

  • Authoritative pentru competitiv si economie; P2P/rollback pentru 1v1/co-op.
  • Transportul conteaza: ENet/QUIC/Steam Sockets reduc jitter si pierderi.
  • Lag compensation corect si prediction reduc perceptia de latency.
  • Planifica costurile compute + egress; delta si AOI scad factura.
  • Testele de retea (loss/jitter) in CI previn surprize in productie.

URMATORUL PAS

Ti-a placut abordarea?

Aplicam aceleasi principii in proiectele clientilor: AI, automatizari, produse care nu se sting dupa lansare.