de Jason Chitla

O poveste jenantă: De ce serverul meu ar putea gestiona doar 10 jucători

Ceea ce ar putea fi și mai jenant este că la un moment dat m-am convins că 10 jucători pe server erau normali.

Totul a început cu o idee la începutul verii. Stăteam în camera mea încercând să mă gândesc la un joc io de făcut (am decis dacă vreau să fac un joc, m-am constrâns să fac un joc io pentru potențialul viral maxim – asta e un lucru, jur).

Așadar, am început să analizez ceea ce făcea anumite jocuri io (agar.io, slither.io etc.) dependență. Găseam comparații și asemănări între astfel de jocuri, așa cum se vede în imaginea de mai jos:

O poveste jenanta De ce serverul meu ar putea gestiona
„Joey o va juca?” -> Joey este fratele meu mai mic la gimnaziu. Scrierea acestei întrebări pe tablă m-a obligat să iau întotdeauna o decizie având în vedere utilizatorii finali (utilizatorii de tip Joey). Inteligent huh.

În cele din urmă, după ceva mai multă brainstorming, am aterizat knckout.io. Este numele jocului. Încercați să rămâneți pe hartă și eliminați-i pe alții. Mi-a plăcut. Comenzi simple, obiectiv clar și un mecanic de joc frumos.

După ce am prezentat cum doream să arate și să simtă jocul, am început să lucrez. Aș veni acasă de la stagiul meu de vară în fiecare zi, mă antrenam, apoi codificam.

Mai întâi am reușit ca jucătorul să se miște cum mi-am dorit. Apoi m-am ocupat de boosting. Apoi ciocnirile. În cele din urmă, jocul a fost gata și gata să fie testat de public. Sau cel puțin așa am crezut …

Weekendul trecut (acum aproximativ o săptămână), am fost cu toții amperat și gata să arăt lumii ceea ce am făcut. Așa că am mers pe interwebs și am găsit un mic subredit numit „playmygame”. Am scris un scurt rezumat și postat it (ps în comentariile postului puteți vedea clar că m-am subliniat cu privire la capacitatea serverului meu). Am asteptat cu rabdare, apoi HUZZAH! S-a alăturat un jucător.

Mergeam înainte și înapoi unul în celălalt în joc. Între timp, eram stresat și îngrijorat de ceea ce gândea acest jucător. După ce acest jucător și-a pierdut toată viața și a fost pornit din meciul în care eram, am așteptat să văd dacă vor reveni. Și au făcut-o! Dar chiar mai bine: jucătorul și-a setat numele „ilikethisgame”. Ochii mi s-au mărit și am avut o goană de adrenalină! Eram cel mai fericit băiat din lume.

În curând s-au alăturat alți jucători și unii au lăsat comentarii la postarea Reddit. Mai mulți jucători au spus că s-au bucurat de joc! Eram extaziat. Apoi am verificat cum rezista serverul meu (pe 8/15) …

1611198127 131 O poveste jenanta De ce serverul meu ar putea gestiona
De pe un server de 1 GB, 1 vCPU Digital Ocean NYC care rulează Ubuntu NodeJS 6.9.5 pe 14.04

Am simțit că cineva mi-a dat vântul. A fost real? Acest lucru trebuia să fie fals, m-am gândit în sinea mea. Doar două jocuri, iar serverului le este greu să le proceseze.

Am început să mă gândesc unde am greșit în codul meu. Credeam că detectarea coliziunilor, cu siguranță, trebuie să fie blocajul. Dar foloseam deja patru arbori pentru a ajuta la reducerea numărului de treceri de detectare a coliziunilor.

A trebuit să fac niște lucruri murdare, așa că am creat un nou server Digital Ocean pentru a-l folosi ca server de dezvoltare. Apoi am dezactivat temporar detectarea coliziunii complet și am văzut că problema era încă acolo.

OK – dacă detectarea coliziunilor nu a fost problema, atunci ce altceva ar putea fi?

M-am gândit la câte informații trimiteam de la server către fiecare client în fiecare secundă. Aveam această funcție de difuzare care trimitea starea jocului la fiecare 22 de milisecunde fiecărui client. În această funcție, am filtrat inutil jucătorul local al clientului dat într-un allPlayers proprietate, doar pentru a pune jucătorul local în propria proprietate. Deci, nu numai că puneam o buclă for (filtrarea) într-o altă buclă for (difuzarea pentru fiecare client), personalizam și datele pentru a fi trimise de această funcție de difuzare pentru fiecare client.

Această personalizare nu a fost necesară. Ar trebui doar să pot trimite starea jocului tuturor fără personalizare. Toată lumea ar trebui să obțină aceleași date (iar datele nu trebuie adaptate la un anumit client). Acesta trebuia să fie locul în care se consumă CPU. Așa că am optimizat această funcție, am împins-o în sus pe serverul dev și am verificat graficul CPU. Nicio remediere.

Cu ignoranța mea, am început să mă conving că ~ 10-20 de jucători pe 1 server de bază erau buni. Acum, cum ajung la o astfel de concluzie? Ei bine, încrederea mea extremă în abilitățile mele tehnice mă orbea în mod clar de realitate. Am dat peste o post unde creatorul agar.io a spus că serverul său de bază poate gestiona aproximativ 190 de jucători. Am ieșit repede din ea.

Următorul vinovat pe care îl aliniasem era: socket.io. Foloseam socket.io pentru a gestiona comunicarea în timp real între client și server. Mai auzisem că socket.io nu era la fel de ușor ca alte alternative.

În trecut, dacă doriți să trimiteți un mesaj în mod asincron, trebuia să implementați un fel de hack: sondaje lungi sau prize flash. Acest lucru se datorează faptului că nu toate browserele web au acceptat webcams. Dar majoritatea browserelor oferă acum suport nativ. Dar, pentru ca socket.io să stabilească o conexiune, aceasta o face mai întâi utilizând unul dintre hacks-urile disponibile menționate, iar apoi îmbunătățește conexiunea dacă clientul acceptă un mod mai bun. Chiar dacă websocket-urile sunt deja acceptate pe scară largă. Această abordare vine în detrimentul procesorului și al memoriei. Dar nu atât cât am crezut …

Am sărit online și am introdus naiv „socket io cpu problem” în Google. Primele rezultate au fost intitulate „Node.js – Cum depanare Node + Socket.io Probleme CPU – Eroare server” și “Node.js – server de nod Socket.io folosind cpu mare – Stack Overflow. ” Mi s-au luminat ochii. Am fost liniștit că acesta este vinovatul problemei mele. Dar am făcut clic pe primul articol și autorul a menționat că are de-a face cu aproximativ 1.500 de conexiuni de socket concurente. Nu sunt specializat în matematică, dar 20 de jucători sunt semnificativ mai mici de 1.500 de jucători.

Doar pentru dracu, am schimbat aplicația Node de pe server pentru a o folosi micile portaluri web, apoi a schimbat aplicația Node din partea clientului pentru a utiliza suportul nativ pentru web, chiar în interiorul browserului. Am împins modificările pe serverul de dezvoltare și am verificat graficul CPU. Nicio remediere.

Moralul meu a fost la un nivel minim. Am început să mă înfund de fiecare dată când trebuia să verific graficul dracului CPU. Am crezut că nu voi obține niciodată acea linie albastră să nu mai fugă de mine. Aceasta a fost singura dată când m-am simțit complet incapabil să fac față unor sarcini tehnice. Dar apoi s-a întâmplat …

Stăteam în fața graficului CPU care se zbătea în nenorocirea mea când am observat ceva. Nu a contat câte jocuri complete rulează sau cât de aproape au început toate. CPU a crescut constant la o rată constantă. Nu rămăsesem niciodată suficient de mult timp pentru a observa acest lucru. Pierdere de memorie!

Mi-am scanat codul, linie cu linie, căutând eroarea (ceea ce ar fi trebuit să fac la început). Acolo era.

În jocul meu, un eveniment este un obiect care captează informații despre lucruri precum moartea jucătorilor, sporurile și coliziunile. Deci, se creează un eveniment de fiecare dată când se întâmplă unul dintre aceste lucruri.

Am această buclă care trece prin fiecare eveniment și o actualizează. Se numește la fiecare 16 ms. După ce un eveniment își îndeplinește datoria, ar trebui să fie șters. Cuvinte cheie: „ar trebui”.

Bingo. Am avut o acumulare de memorie, precum și o cantitate tot mai mare de treceri inutile pentru buclă. Am inserat o linie de cod și voila!

1611198128 169 O poveste jenanta De ce serverul meu ar putea gestiona
bine voi fi

Oftat uriaș de ușurare.

Următoarea mea sarcină este să văd câte jocuri (4 jucători pe joc) pe care un server le poate suporta acum fără probleme. (Știu cel puțin 12 jocuri, dar încă nu am încercat mai multe). Acum, că știu că numărul de evenimente are un impact uriaș asupra procesorului … ce se va întâmpla în producție când toți jucătorii declanșează evenimente de amplificare, coliziune și moarte în fiecare secundă? Testele mele nu au explicat acest lucru.

De asemenea, după ce această postare devine virală, iar jocul meu urmează exemplul, va trebui să măresc rapid numărul de servere disponibile. Voi face ca subiectul unei postări viitoare împreună cu: „Cum knckout.io a crescut la milioane de jucători. ” Urmăriți-mă aici pentru actualizări. 🙂