Kínos mese: Miért tudott csak 10 játékost kezelni a szerverem?

Ami még kínosabb lehet, hogy egy ponton meggyőztem magam arról, hogy szerverenként 10 játékos normális.

Az egész egy ötlettel kezdődött a nyár elején. Álltam a szobámban, és megpróbáltam elképzelni egy elkészítendő io játékot (úgy döntöttem, hogy játékot készítek, arra kényszerítettem magam, hogy io játékot készítsek a maximális víruspotenciál érdekében - esküszöm, ez egy dolog).

Szóval elkezdtem elemezni, hogy mi okoz bizonyos addiktív játékokat (agar.io, slither.io stb.) Függőséget. Összehasonlításokat és hasonlóságokat találtam az ilyen játékok között, amint az az alábbi képen látható:

Végül egy kis ötletelés után landoltam a knckout.io oldalon. Ez a játék neve. Próbáljon meg maradni a térképen, és leütni másokat. Szerettem. Egyszerű kezelőszervek, tiszta objektív és gyönyörű játékszerelő.

Miután megfogalmaztam, hogyan akarom a játék kinézetét és érzését, dolgozni kezdtem. Mindennap hazajönnék a nyári szakmai gyakorlatomból, edzeni, majd kódolni.

Először arra késztettem a játékost, hogy mozogjon, ahogy akarom. Aztán kezeltem az erősítést. Aztán az ütközések. Végül a játék elkészült, és készen állt a nyilvánosság tesztelésére. Vagy legalábbis azt hittem ...

A múlt hétvégén (kb. Egy hete) mindannyian lelkesedtem, és készen állok arra, hogy megmutassam a világnak, mit készítettem. Ezért beléptem az internetes hálózatokba, és találtam egy kicsi „playmygame” nevű alprogramot. Felírtam egy rövid összefoglalót és elküldtem (a bejegyzés megjegyzései között jól látható, hogy a szerverem képességeire hangsúlyoztam). Türelmesen vártam, aztán HUZZAH! Egy játékos csatlakozott.

A játékban össze-vissza haladtunk. Közben stresszeltem és aggódtam, hogy mire gondol ez a játékos. Miután ez a játékos életét vesztette, és kirúgták a meccsről, ahol voltunk, vártam, hogy visszatérjenek-e. És megtették! De még jobb: a játékos az „ilikethisgame” névre állította a nevét. A szemem tágra nyílt, és adrenalin-hullám volt! Én voltam a legboldogabb fiú a világon.

Hamarosan más játékosok is csatlakoztak, és néhányan megjegyzést fűztek a Reddit bejegyzéséhez. Több játékos azt mondta, hogy élvezték a játékot! Eksztatikus voltam. Aztán megnéztem, hogy áll a szerverem (15/15-én) ...

Olyan érzés volt, mintha valaki kiütötte volna belőlem a szelet. Valódi volt? Ennek hamisnak kellett lennie, gondoltam magamban. Csak két játék, és a szerver nehezen tudja feldolgozni őket.

Elkezdtem gondolkodni azon, hogy hol tévedtem a kódomban. Úgy gondoltam, hogy az ütközésészlelésnek bizonyosan a szűk keresztmetszetnek kell lennie. De már négyzetfákat használtam az ütközés-felderítési passzok szűkítéséhez.

Piszkos munkát kellett végeznem, ezért felpörgettem egy új Digital Ocean szervert, amelyet fejlesztői kiszolgálóként használhattam. Ezután ideiglenesen teljesen letiltottam az ütközésészlelést, és láttam, hogy a probléma továbbra is fennáll.

OK - ha az ütközés észlelése nem jelentett problémát, akkor mi lehet más?

Arra gondoltam, hogy másodpercenként mennyi információt küldök a szerverről az egyes klienseknek. Nekem volt ez a sugárzási funkcióm, amely 22 ezredmásodpercenként küldte el a játék állapotát minden egyes ügyfélnek. Ebben a funkcióban feleslegesen szűrtem le az adott kliens helyi játékosát egy allPlayersingatlanban, csak azért, hogy a helyi játékost a saját tulajdonába helyezzem. Tehát nemcsak egy for for ciklust (a szűrést) tettem egy másik ciklusba (az egyes kliensek adása), hanem az egyes futtatási funkciók által küldendő adatokat is testre szabtam minden kliens számára.

Erre a testreszabásra nem volt szükség. Csak képesnek kellene lennem elküldeni mindenkinek a játék állapotát testreszabás nélkül. Mindenkinek ugyanazokat az adatokat kell kapnia (és az adatokat nem szabad egy adott ügyfélhez szabni). Ebben kellett lennie a CPU-nak. Tehát optimalizáltam ezt a funkciót, feltoltam a dev szerverre, és megnéztem a CPU grafikont. Nincs javítás.

Tudatlanságommal kezdtem meggyőzni magam arról, hogy 1 magszerverenként ~ 10–20 játékos jó. Most hogyan juthatok ilyen következtetésre? Nos, a technikai képességeim iránti rendkívüli bizalom egyértelműen elvakította a valóságtól. Belebotlottam egy bejegyzésbe, ahol az agar.io készítője azt mondta, hogy az 1 mag szervere körülbelül 190 játékost képes kezelni. Gyorsan kipattantam belőle.

A következő tettes, akit felsorakoztam: socket.io. A socket.io fájlt használtam az ügyfél és a szerver közötti valós idejű kommunikáció kezelésére. Korábban hallottam, hogy a socket.io nem volt olyan könnyű, mint más alternatívák.

A nap folyamán, ha aszinkron módon akart üzenetet küldeni, akkor valamiféle hacket kellett végrehajtania: hosszú lekérdezést vagy flash foglalatokat. Ennek oka az volt, hogy nem minden webböngésző támogatta a webaljzatokat. De a legtöbb böngésző már natív támogatást kínál. De ahhoz, hogy a socket.io kapcsolat létrejöjjön, először az említett elérhető hackek egyikével teszi, majd frissíti a kapcsolatot, ha az ügyfél jobb módot támogat. Annak ellenére, hogy a webaljzatok már széles körben támogatottak. Ez a megközelítés a CPU és a memória rovására megy. De nem annyira, mint gondoltam volna ...

Ugráltam az interneten, és naivan beírtam a „socket io cpu problem” -t a Google-be. Az első pár eredmény a következő címet kapta: „Node.js - A Node + Socket.io CPU-problémák hibakeresése - Kiszolgáló hiba” és „Node.js - Socket.io csomópont-kiszolgáló magas CPU-t használva - Verem túlcsordulás” címmel. Felcsillant a szemem. Megnyugodtam, hogy ez a bűnös a problémámban. De rákattintottam az első cikkre, és a szerző megemlítette, hogy ~ 1500 egyidejű socket csatlakozással foglalkozik. Nem vagyok matematika szak, de 20 játékos lényegesen kevesebb, mint 1500 játékos.

Csak a fenébe, a kiszolgálóoldali Node alkalmazást kicsiny webhálózatok használatára váltottam, majd az ügyféloldali Node alkalmazást natív webhálózati támogatás használatára, közvetlenül a böngészőben. Felhúztam a változásokat a dev szerverre, és megnéztem a CPU grafikont. Nincs javítás.

A morálom mindig alacsony volt. Minden alkalommal görcsölni kezdtem, amikor meg kellett vizsgálnom az átkozott CPU grafikont. Azt hittem, soha nem fogom elérni azt a kék vonalat, hogy ne meneküljek előlem. Ez volt az egyetlen alkalom, amikor valaha is teljesen képtelennek éreztem magam valamilyen technikai feladat kezelésére. De aztán megtörtént…

A CPU-grafikon előtt ültem, amely a nyomorúságomban hevert, amikor észrevettem valamit. Nem számított, hogy hány teljes játék fut, vagy hogy milyen szorosan indulnak egymás mellett. A CPU folyamatosan, állandó sebességgel növekedett. Soha nem tartózkodtam elég sokáig a megfigyeléshez. Memóriaszivárgás!

Soronként vizsgáltam a kódomat, és kerestem a hibát (amit már a legelején meg kellett volna tennem). Ott volt.

A játékomban egy esemény egy olyan objektum, amely információkat rögzít például a játékosok haláláról, növeléséről és ütközéséről. Tehát minden alkalommal létrejön egy esemény, amikor az egyik ilyen dolog megtörténik.

Van ez a hurok, amely minden eseményen végigmegy és frissíti. 16 ms-onként hívják. Miután egy esemény teljesíti kötelességét, azt törölni kell. Kulcsszavak: „állítólag”.

Bingó. Halmoztam a memóriát, valamint egyre több a felesleges hurok-áthaladás. Beillesztettem egy kódsort és voila!

Hatalmas megkönnyebbülés.

A következő feladatom az, hogy megnézzem, egy szerver hány játékot (játékonként 4 játékost) tud már simán támogatni. (Legalább 12 játékát ismerem, de többet még nem próbáltam). Most, hogy tudom, hogy az események száma óriási hatást gyakorol a CPU-ra ... mi fog történni a gyártásban, amikor minden játékos másodpercenként lökést indít, ütközést és halálesetet? A tesztjeim nem vették figyelembe ezt.

Továbbá, miután ez a bejegyzés vírussá válik, és a játékom követi ezt a példát, gyorsan át kell méreteznem az elérhető szerverek számát. Ezt a témát egy későbbi bejegyzéssel fogom megfogalmazni: „Hogyan nőtt a knckout.io játékosok millióihoz?” Kövessen itt a frissítésekért. :)