Hämmentävä tarina: Miksi palvelimeni pystyi käsittelemään vain 10 pelaajaa

Mikä voi olla vielä noloa, on se, että olin yhdessä vaiheessa vakuuttanut itseni, että 10 pelaajaa palvelinta kohden oli normaalia.

Kaikki alkoi ideasta kesän alussa. Seisoin huoneessani yrittäen ajatella tekemistäni io-peliä (päätin tehdä pelin, pakotin itseni tekemään io-pelin maksimaalisen viruspotentiaalin saavuttamiseksi - vannon).

Joten aloin analysoida, mikä teki tietyistä io-peleistä (agar.io, slither.io jne.) Riippuvuutta. Löysin vertailuja ja yhtäläisyyksiä tällaisten pelien välillä, kuten alla olevassa kuvassa näkyy:

Lopuksi, vähän enemmän aivoriihiä, laskeuduin osoitteeseen knckout.io. Se on pelin nimi. Yritä pysyä kartalla ja kaataa muut pois. Minä rakastin sitä. Yksinkertaiset hallintalaitteet, selkeä tavoite ja kaunis pelimekaanikko.

Kun olen selvittänyt kuinka halusin pelin näyttävän ja tuntuvan, pääsin töihin. Tulisin kotiin kesäharjoittelustani joka päivä, harjoittelemaan ja sitten koodaamaan.

Sain pelaajan ensin liikkumaan haluamallani tavalla. Sitten hoidin tehostuksen. Sitten törmäykset. Lopuksi peli oli valmis ja valmis testaamaan yleisöä. Tai niin ajattelin ...

Viime viikonloppuna (noin viikko sitten) olin kaikki innoissaan ja valmis näyttämään maailmalle tekemäni. Joten menin verkkoihin ja löysin pienen subredditin nimeltä "playmygame". Kirjoitin lyhyen yhteenvedon ja lähetin sen (ps postin kommenteista, joista näet selvästi, että korostin palvelimeni kykyä). Odotin kärsivällisesti, sitten HUZZAH! Pelaaja oli liittynyt.

Menimme edestakaisin toisiinsa pelissä. Sillä välin korostin ja olin huolissani siitä, mitä tämä pelaaja ajatteli. Sen jälkeen kun tämä pelaaja menetti koko henkensä ja oli saanut potkut ottelusta, jossa olimme, odotin, tuleeko he takaisin. Ja he tekivät! Mutta vielä parempi: pelaaja asettaa nimensä "ilikethisgame". Silmäni kasvoivat leveiksi ja minulla oli adrenaliinia! Olin maailman onnellisin poika.

Pian muut pelaajat liittyivät ja jotkut jättivät kommentteja Reddit-viestiin. Useat pelaajat sanoivat nauttineensa pelistä! Olin hurmioitunut. Sitten tarkistin, kuinka palvelimeni pysyi kiinni (8/15) ...

Tuntui kuin joku olisi pudonnut tuulen minusta. Oliko tämä totta? Tämän piti olla väärennös, ajattelin itsekseni. Vain kaksi peliä ja palvelimella on vaikeuksia käsitellä niitä.

Aloin miettiä missä menin pieleen koodissani. Luulin, että törmäystunnistuksen oli varmasti oltava pullonkaula. Mutta käytin jo nelipuuta auttaakseni kaventamaan törmäystunnistuskäyntien määrää.

Minun täytyi tehdä likaista työtä, joten kehräsin uuden Digital Ocean -palvelimen käytettäväksi kehityspalvelimeni. Poistin törmäystunnistuksen väliaikaisesti kokonaan ja huomasin, että ongelma oli edelleen olemassa.

OK - jos törmäystunnistaminen ei ollut ongelma, niin mitä muuta se voisi olla?

Ajattelin kuinka paljon tietoa lähetin palvelimelta kullekin asiakkaalle sekunnissa. Minulla oli tämä lähetystoiminto, joka lähetti pelin tilan 22 millisekunnin välein kullekin asiakkaalle. Tässä toiminnossa suodatin tarpeettomasti tietyn asiakkaan paikallisen pelaajan allPlayersomaisuuteen vain asettamaan paikallisen pelaajan omaan omaisuuteensa. Joten, paitsi laitoin for for -silmukan (suodatus) toiseen silmukalle (lähetys jokaiselle asiakkaalle), myös mukautin tämän lähetystoiminnon lähettämiä tietoja jokaiselle asiakkaalle.

Mukauttaminen ei ollut välttämätöntä. Minun pitäisi vain pystyä lähettämään pelin tila kaikille ilman mukautuksia. Kaikkien tulisi saada samat tiedot (eikä tietoja tulisi räätälöidä tietylle asiakkaalle). Tämän oli oltava siellä missä CPU syötään. Joten optimoin tämän toiminnon, työnsin sen ylös dev-palvelimeen ja tarkistin suorittimen kaavion. Ei korjausta.

Tietämättömyydelläni aloin vakuuttaa itseni siitä, että ~ 10–20 pelaajaa per ydinpalvelin oli hyvä. Kuinka pääsen nyt tällaiseen johtopäätökseen? No, äärimmäinen luottamus teknisiin kykyihini sokaisi selvästi todellisuudesta. Törmäsin viestiin, jossa agar.io: n luoja sanoi, että hänen yksi ydinpalvelin pystyy käsittelemään noin 190 pelaajaa. Napsautin nopeasti siitä.

Seuraava syyllinen, jonka olin asettanut riviin, oli: socket.io. Käytin socket.io -ohjelmaa hallita reaaliaikaista tiedonsiirtoa asiakkaan ja palvelimen välillä. Olin kuullut aiemmin, että socket.io ei ollut yhtä kevyt kuin muut vaihtoehdot.

Päivän aikana, jos halusit lähettää viestin asynkronisesti, joudut toteuttamaan jonkinlaisen hakkeroinnin: pitkät äänestykset tai flash-pistorasiat. Tämä johtui siitä, että kaikki verkkoselaimet eivät tue verkkopistokkeita. Mutta useimmat selaimet tarjoavat nyt natiivitukea. Mutta jotta socket.io voi muodostaa yhteyden, se tekee sen ensin käyttämällä jotakin mainituista hakkerista ja päivittää sitten yhteyden, jos asiakas tukee parempaa tapaa. Vaikka verkkoliittimiä tuetaan jo laajalti. Tämä lähestymistapa tulee suorittimen ja muistin kustannuksella. Mutta ei niin paljon kuin olin ajatellut ...

Hyppäsin verkossa ja kirjoitin naiivisti "socket io cpu problem" Googleen. Ensimmäisten parien tulosten otsikot olivat "Node.js - Node + Socket.io -prosessorin ongelmien virheenkorjaus - palvelinvirhe" ja "Node.js - Socket.io-solmupalvelin, joka käyttää suurta prosessoria - pinon ylivuoto." Silmäni syttyivät. Minua vakuutti, että tämä oli ongelmani syyllinen. Mutta napsautin ensimmäistä artikkelia ja kirjoittaja mainitsi, että hän käsitteli ~ 1 500 samanaikaista pistokeliitäntää. En ole matematiikan pääaine, mutta 20 pelaajaa on huomattavasti alle 1500 pelaajaa.

Pelkästään sen vuoksi, vaihdoin palvelinpuolen Node-sovelluksen käyttämään pieniä verkkopistokkeita, sitten vaihdoin asiakaspuolen Node-sovelluksen käyttämään natiivia verkkopistetukea suoraan selaimen sisällä. Työnsin muutokset ylös dev-palvelimeen ja tarkistin suorittimen kaavion. Ei korjausta.

Moraalini oli kaikkien aikojen matala. Aloin rypistyä joka kerta, kun jouduin tarkistamaan kultaisen CPU-käyrän. Luulin, etten koskaan saisi sitä sinistä viivaa lopettamaan pakenemista minulta. Tämä oli ainoa kerta, kun tunsin olevani täysin kykenemätön käsittelemään teknistä tehtävää. Mutta sitten se tapahtui…

Istuin CPU-kaavion edessä, joka upposi kurjuudessani, kun huomasin jotain. Ei ollut väliä kuinka monta täyttä peliä oli käynnissä tai kuinka lähellä toisiaan kaikki aloitettiin. Suoritin kasvoi tasaisesti tasaisella nopeudella. En ollut koskaan viipynyt tarpeeksi kauan tarkkaillakseni tätä. Muistivuoto!

Skannasin koodini rivi riviltä etsimällä virhettä (mikä minun olisi pitänyt tehdä alussa). Siinä se oli.

Pelissäni tapahtuma on esine, joka tallentaa tietoja esimerkiksi pelaajien kuolemista, korotuksista ja törmäyksistä. Joten tapahtuma luodaan aina, kun jokin näistä tapahtuu.

Minulla on tämä silmukka, joka käy läpi jokaisen tapahtuman ja päivittää sen. Sitä kutsutaan 16 ms: n välein. Kun tapahtuma täyttää velvollisuutensa, se on tarkoitus poistaa. Avainsanat: "piti".

Bingo. Minulla oli muistia kasaantumassa ja yhä enemmän tarpeettomia silmukan läpäisyjä. Lisäsin koodirivin ja voila!

Valtava helpotuksen huokaus.

Seuraava tehtäväni on nähdä, kuinka monta peliä (4 pelaajaa per peli) yksi palvelin voi nyt tukea sujuvasti. (Tiedän sen vähintään 12 peliä, mutta en ole vielä kokeillut enemmän). Nyt kun tiedän, että tapahtumien lukumäärällä on valtava vaikutus prosessoriin ... mitä tapahtuu tuotannossa, kun kaikki pelaajat ampuvat joka toinen sekunti tehostamis-, törmäys- ja kuolemantapahtumia? Testeissäni ei ole otettu huomioon sitä.

Lisäksi, kun tämä viesti tulee virukseksi ja pelini seuraa esimerkkiä, minun on nopeasti skaalattava käytettävissä olevien palvelimien määrä. Teen tämän tulevan viestin aiheen yhdessä: "Kuinka knckout.io kasvoi miljooniksi pelaajiksi." Seuraa minua täällä päivityksiä varten. :)