ProHoster > Blog > Adminisztráció > Nyílt forráskódú felhős játék a WebRTC-n: p2p, többjátékos, nulla késleltetés
Nyílt forráskódú felhős játék a WebRTC-n: p2p, többjátékos, nulla késleltetés
Szoftver mint szolgáltatás, infrastruktúra mint szolgáltatás, platform mint szolgáltatás, kommunikációs platform mint szolgáltatás, videokonferencia mint szolgáltatás, mi a helyzet a felhőjátékkal mint szolgáltatással? Már több kísérlet is történt felhőjáték (Cloud Gaming) létrehozására, mint például a Google által nemrégiben elindított Stadia. Stadia nem új a WebRTC-ben, de mások is használhatják ugyanígy a WebRTC-t?
Thanh Nguyen úgy döntött, hogy kipróbálja ezt a lehetőséget nyílt forráskódú CloudRetro projektjén. A CloudRetro a Pionon alapul, népszerű Go alapú WebRTC könyvtár (köszönjük Látható a Pion fejlesztőcsapatától a cikk elkészítésében nyújtott segítségükért). Ebben a cikkben Thanh áttekintést ad projektje felépítéséről, és arról is beszél, hogy milyen hasznos dolgokat tanult, és milyen kihívásokkal találkozott munkája során.
Belépés
Tavaly, amikor a Google bejelentette a Stadiát, felrobbant a fejemben. Az ötlet annyira egyedi és innovatív, hogy folyamatosan azon töprengtem, hogyan lehetséges ez a meglévő technológiával. A téma jobb megértésének vágya késztetett arra, hogy elkészítsem egy nyílt forráskódú felhőjáték saját verzióját. Az eredmény egyszerűen fantasztikus volt. Az alábbiakban szeretném megosztani az évemmel való munka folyamatát projekt.
TLDR: rövid diaváltozat kiemelésekkel
Miért a felhőjáték a jövő?
Úgy gondolom, hogy a Cloud Gaming hamarosan nemcsak a játék, hanem a számítástechnika más területeinek következő generációja lesz. A felhőalapú játék a kliens/szerver modell csúcsa. Ez a modell maximalizálja a háttérrendszer kezelését és minimalizálja az előtérben végzett munkát azáltal, hogy távoli szerveren tárolja a játéklogikát, és streameli a képeket/hangot az ügyfélnek. A kiszolgáló végzi a nehéz feldolgozást, így a kliens többé nincs kitéve a hardveres korlátoknak.
A Google Stadia lényegében lehetővé teszi a játékot AAA játékok (vagyis csúcskategóriás kasszasiker játékok) egy olyan felületen, mint a YouTube. Ugyanez a módszer alkalmazható más nehéz offline alkalmazásoknál is, mint például az operációs rendszer vagy a 2D/3D grafikai tervezés stb. hogy konzisztensen futtathassuk őket alacsony specifikációjú eszközökön több platformon.
A technológia jövője: Képzeld el, ha a Microsoft Windows 10 futna a Chrome böngészőn?
A felhőalapú játék technikailag kihívást jelent
A játék azon ritka területek egyike, ahol állandó, gyors felhasználói reakcióra van szükség. Ha időnként 2 másodperces késéssel találkozunk az oldalra kattintva, ez elfogadható. Az élő videó streamek általában néhány másodperces késéssel jelennek meg, de továbbra is ésszerű használhatóságot kínálnak. Ha azonban a játék gyakran 500 ms-ot késik, akkor egyszerűen nem játszható. Célunk rendkívül alacsony késleltetés elérése, hogy a bemenet és a média közötti rés a lehető legkisebb legyen. Ezért a video streaming hagyományos megközelítése itt nem alkalmazható.
Általános felhő játéksablon
Nyílt forráskódú projekt CloudRetro
Úgy döntöttem, készítek egy tesztmintát egy felhőjátékból, hogy megnézzem, mindez lehetséges-e ilyen szigorú hálózati korlátozások mellett. A Golangot választottam a koncepció bizonyítására, mert ez volt az a nyelv, amelyet a legjobban ismertem, és sok más okból is alkalmas volt erre a megvalósításra, ahogy később felfedeztem. A Go egyszerű és nagyon gyorsan fejlődik; A Go csatornái nagyszerűek a többszálú kezelés kezelésére.
Terv CloudRetro.io egy nyílt forráskódú felhőalapú játékszolgáltatás retro játékokhoz. A projekt célja, hogy a legkényelmesebb játékélményt hozza a hagyományos retro játékokba, és hozzáadja a többjátékos módot.
Itt tudhat meg többet a projektről: https://github.com/giongto35/cloud-game.
CloudRetro funkció
A CloudRetro retro játékokat használ a felhőalapú játék erejének bemutatására. Ez lehetővé teszi számos egyedi játékélmény megszerzését.
A játék hordozhatósága
Azonnali lejátszás az oldal megnyitásakor; nincs szükség letöltésre vagy telepítésre
Mobilböngészőben működik, így futtatásához nincs szükség szoftverre
A játékmenetek több eszköz között is megoszthatók, és a felhőben tárolhatók a következő bejelentkezéshez
A játék streamelhető, vagy akár több felhasználó is játszhatja egyszerre:
Crowdplay, mint a TwitchPlayPokemon, csak több platformon és valós időben
Offline játékok online. Sok felhasználó hálózat beállítása nélkül is tud játszani. A Samurai Shodownt mostantól 2 játékos játszhatja a CloudRetro hálózaton keresztül
Online többjátékos játék demóverziója különböző eszközökön
Infrastruktúra
Követelmények és technológiai halom
Az alábbiakban felsoroljuk azokat a követelményeket, amelyeket a projekt elindítása előtt állítottam fel.
1. Egy játékos
Ez a követelmény itt talán nem tűnik túl fontosnak vagy nyilvánvalónak, de ez az egyik kulcsfontosságú dolog, lehetővé teszi, hogy a felhőalapú játék a lehető legtávolabb maradjon a hagyományos streaming szolgáltatásoktól. Ha egyjátékos játékra koncentrálunk, akkor megszabadulhatunk a központosított szervertől vagy CDN-től, mert nem kell tömegekhez streamelnünk. Ahelyett, hogy adatfolyamokat töltenének fel egy fogadó kiszolgálóra, vagy csomagokat továbbítanának egy központi WebSocket szerverre, a szolgáltatásfolyamok közvetlenül a felhasználóhoz jutnak el egy peer-to-peer WebRTC kapcsolaton keresztül.
2. Alacsony késleltetésű médiafolyam
A Stadiáról olvasva gyakran látom, hogy egyes cikkekben említik a WebRTC-t. Rájöttem, hogy a WebRTC egy kiemelkedő technológia, és tökéletes a felhőalapú játékokhoz. A WebRTC egy olyan projekt, amely valós idejű kommunikációt biztosít webböngészőknek és mobilalkalmazásoknak egy egyszerű API-n keresztül. Peer-to-peer kapcsolatot biztosít, médiára van optimalizálva, és szabványos beépített kodekekkel rendelkezik, mint például a VP8 és a H264.
Előnyben részesítettem a lehető legjobb felhasználói élmény biztosítását, mint a jó minőségű grafika fenntartását. Néhány veszteség elfogadható az algoritmusban. A Google Stadiának van egy további lépése, hogy csökkentse a képméretet a szerveren, és a képkockákat a rendszer jobb minőségre skálázza, mielőtt továbbítaná őket a többieknek.
3. Elosztott infrastruktúra földrajzi útválasztással
Nem számít, mennyire optimalizált a tömörítési algoritmus és a kód, a hálózat továbbra is a döntő tényező, amely leginkább hozzájárul a késleltetéshez. Az architektúrának rendelkeznie kell egy olyan mechanizmussal, amely párosítja a felhasználóhoz legközelebbi kiszolgálót az oda-vissza úti idő (RTT) csökkentése érdekében. Az architektúrának 1 koordinátorral és több streaming szerverrel kell rendelkeznie, amelyek szerte a világon vannak elosztva: US West, US East, Europe, Singapore, China. Minden streaming szervert teljesen el kell különíteni. A rendszer módosíthatja elosztását, amikor egy szerver csatlakozik a hálózathoz, vagy elhagyja azt. Így nagy forgalom esetén további szerverek hozzáadása lehetővé teszi a vízszintes méretezést.
4. Böngésző kompatibilitás
A felhőalapú játék akkor a legjobb, ha a legkevesebbet követeli meg a felhasználóktól. Ez azt jelenti, hogy böngészőben is futtatható. A böngészők segítenek abban, hogy a játékélmény a lehető legkényelmesebb legyen a felhasználók számára, megkímélve őket a szoftver és hardver telepítésétől. A böngészők emellett többplatformos funkcionalitást biztosítanak a mobil és az asztali verziók között. Szerencsére a WebRTC számos böngészőben jól támogatott.
5. A játékfelület és a szolgáltatás egyértelmű szétválasztása
A felhőalapú játékszolgáltatást platformnak tekintem. Mindenkinek képesnek kell lennie bármit csatlakoztatni a platformhoz. Most integráltam LibRetro felhős játékszolgáltatással, mert a LibRetro gyönyörű játékemulátor felületet kínál az olyan retro játékokhoz, mint a SNES, GBA, PS.
6. Szobák többjátékos játékhoz, tömegjátékhoz és külső kapcsolathoz (mély kapcsolat) a játékhoz
A CloudRetro számos új játékmenetet támogat, mint például a CrowdPlay és az Online MultiPlayer retro játékokhoz. Ha több felhasználó nyitja meg ugyanazt a mélyhivatkozást különböző számítógépeken, ugyanazt a futó játékot látják, és még csatlakozhatnak is hozzá.
Sőt, a játékállapotokat felhőtárhelyen tárolják. Ezzel a felhasználók bármikor folytathatják a játékot bármely más eszközön.
7. Vízszintes méretezés
Mint manapság minden SAAS-t, a felhőalapú játékot is úgy kell megtervezni, hogy vízszintesen méretezhető legyen. A koordinátor-dolgozó kialakítás lehetővé teszi, hogy több alkalmazottat vegyen fel a nagyobb forgalom kiszolgálása érdekében.
8. Nincs kapcsolat egyetlen felhőhöz
A CloudRetro infrastruktúráját különböző felhőszolgáltatók (Digital Ocean, Alibaba, egyéni szolgáltató) tárolják a különböző régiókban. Engedélyezem a Docker-tárolóban való futtatást az infrastruktúra számára, és konfigurálom a hálózati beállításokat egy bash-szkript segítségével, hogy elkerüljem, hogy egyetlen felhőszolgáltatóhoz zárjak. Ha ezt kombináljuk a WebRTC NAT Traversal szolgáltatásával, rugalmasan telepíthetjük a CloudRetro-t bármely felhőplatformon, sőt bármely felhasználó gépén.
Építészeti tervezés
Munkás: (vagy a fent említett streaming szerver) megsokszorozza a játékokat, futtatja a kódolási folyamatot, és a kódolt médiát továbbítja a felhasználóknak. A Worker-példányok az egész világon el vannak terjesztve, és minden dolgozó egyszerre több felhasználói munkamenetet is kezelhet.
Koordinátor: felelős azért, hogy az új felhasználót a streamelésre legalkalmasabb dolgozóval párosítsa. A koordinátor a WebSocketen keresztül kommunikál a dolgozókkal.
A játék állapotának tárolása: központi távoli tároló minden játékállapothoz. Ez a tároló fontos funkciókat biztosít, mint például a távoli mentés/betöltés.
A CloudRetro legfelső szintű architektúrája
Egyéni szkript
Amikor egy új felhasználó megnyitja a CloudRetro alkalmazást az alábbi ábrán látható 1. és 2. lépésben, a koordinátor az elérhető dolgozók listájával együtt az első oldalra kerül. Ezt követően a 3. lépésben az ügyfél HTTP ping kéréssel kiszámítja az összes jelölt késleltetését. Ezt a késések listáját ezután visszaküldik a koordinátornak, hogy meghatározhassa a felhasználó kiszolgálására legmegfelelőbb dolgozót. Az alábbi 4. lépés létrehozza a játékot. WebRTC adatfolyam-kapcsolat jön létre a felhasználó és a hozzárendelt dolgozó között.
Felhasználói szkript a hozzáférés megszerzése után
Mi van a munkás belsejében
A játék- és adatfolyam-folyamatokat a dolgozóban elkülönítve tárolják, és ott az interfészen keresztül információt cserélnek. Jelenleg ez a kommunikáció a memóriában lévő adatok átvitelével történik Golang csatornák ugyanabban a folyamatban. A következő cél a szegregáció, azaz. a játék független elindítása egy másik folyamatban.
A munkavállalói alkatrészek kölcsönhatása
Fő összetevők:
WebRTC: egy kliens komponens, amely elfogadja a felhasználói bevitelt, és kódolt adathordozót ad ki a szerverről.
Játék emulátor: játék komponens. A Libretro könyvtárnak köszönhetően a rendszer képes futtatni a játékot ugyanazon a folyamaton belül, és belsőleg elfogja a médiát és a bemeneti adatfolyamot.
A játékon belüli képkockákat rögzíti és elküldi a kódolónak.
Kép/audio kódoló: egy kódolási folyamat, amely médiakockákat vesz fel, kódolja azokat a háttérben, és kódolt képeket/hangot ad ki.
Реализация
A CloudRetro a WebRTC-re támaszkodik gerinctechnológiájaként, ezért mielőtt belemerülnék a Golang megvalósítás részleteibe, úgy döntöttem, hogy magáról a WebRTC-ről beszélek. Ez egy csodálatos technológia, amely nagymértékben segített abban, hogy elérjem a másodperc alatti késleltetést a streaming adatokhoz.
WebRTC
A WebRTC-t úgy tervezték, hogy egyszerű API-k segítségével kiváló minőségű peer-to-peer kapcsolatokat biztosítson natív mobilalkalmazásokon és böngészőkön.
NAT átjárás
A WebRTC a NAT Traversal funkciójáról ismert. A WebRTC-t peer-to-peer kommunikációra tervezték. Célja, hogy megtalálja a legmegfelelőbb közvetlen útvonalat, elkerülve a NAT átjárókat és tűzfalakat a peer-to-peer kommunikációhoz egy ún. ICE. Ennek a folyamatnak a részeként a WebRTC API-k STUN szerverek segítségével megtalálják az Ön nyilvános IP-címét, és továbbítják azt a közvetítő szervernek (FORDULAT), ha nem létesíthető közvetlen kapcsolat.
A CloudRetro azonban nem használja ki teljesen ezt a funkciót. Peer-to-peer kapcsolatai nem a felhasználók, hanem a felhasználók és a felhőkiszolgálók között léteznek. A modell szerveroldala kevesebb közvetlen kommunikációs korlátozással rendelkezik, mint egy tipikus felhasználói eszköz. Ez lehetővé teszi a bejövő portok előzetes megnyitását vagy a nyilvános IP-címek közvetlen használatát, mivel a szerver nem áll NAT mögött.
Korábban a projektet a Cloud Gaming játékterjesztési platformjává akartam alakítani. Az ötlet az volt, hogy lehetővé tegyék a játékok készítői számára, hogy játékokat és streamelési forrásokat biztosítsanak. A felhasználók pedig közvetlenül kapcsolatba lépnének a szolgáltatókkal. Ilyen decentralizált módon a CloudRetro csak egy keretrendszer a harmadik féltől származó streamelési erőforrások felhasználókhoz való csatlakoztatásához, így jobban méretezhető, ha már nincs hosztolva. A WebRTC NAT Traversal szerepe nagyon fontos, hogy megkönnyítse a peer-to-peer kapcsolat inicializálását harmadik féltől származó streaming erőforrásokon, megkönnyítve az alkotó számára a hálózathoz való csatlakozást.
Videó tömörítés
A videotömörítés a csővezeték nélkülözhetetlen része, és nagyban hozzájárul a zökkenőmentes áramláshoz. Noha nem szükséges ismerni a VP8/H264 videókódolás minden részletét, a fogalmak megértése segíthet megérteni a streaming videó sebességi beállításait, a váratlan viselkedések hibakeresését és a késleltetés beállítását.
A videó tömörítése egy streaming szolgáltatáshoz kihívást jelent, mert az algoritmusnak biztosítania kell, hogy a teljes kódolási idő + hálózati átviteli idő + dekódolási idő a lehető legalacsonyabb legyen. Ezenkívül a kódolási folyamatnak következetesnek és folyamatosnak kell lennie. Néhány kódolási kompromisszum nem érvényes – például nem részesíthetjük előnyben a hosszú kódolási időket a kisebb fájlméretekkel és dekódolási időkkel szemben, illetve nem alkalmazhatunk következetlen tömörítést.
A videotömörítés mögött meghúzódó ötlet az, hogy kiküszöbölje a szükségtelen információkat, miközben a felhasználók számára elfogadható pontossági szintet tart fenn. Az egyes statikus képkockák kódolása mellett az algoritmus az előző és a következő képkockákból következtet az aktuális képkockára, így csak azok különbségét küldi el. Amint a Pacman példájából látható, csak a differenciálpontokat továbbítják.
Videókockák összehasonlítása Pacman példaként
Hangtömörítés
Hasonlóképpen, a hangtömörítési algoritmus kihagyja az emberek által nem észlelhető adatokat. Az Opus jelenleg a legjobban teljesítő audiokodek. Úgy tervezték, hogy hanghullámot továbbítson egy rendezett datagram protokollon, például az RTP-n (Real Time Transport Protocol) keresztül. A késleltetési ideje alacsonyabb, mint az mp3 és az aac, a minősége pedig jobb. A késleltetés általában 5-66,5 ms körül van.
Pion, WebRTC Golangban
pion egy nyílt forráskódú projekt, amely a WebRTC-t Golangba hozza. A natív C++ WebRTC-könyvtárak szokásos burkolása helyett a Pion a WebRTC natív Golang-megvalósítása jobb teljesítménnyel, Go-integrációval és verziókezeléssel a WebRTC protokollokon.
A könyvtár emellett lehetővé teszi a streamelést is sok nagyszerű beépített beépítettséggel, másodperc alatti késleltetéssel. Megvan a saját megvalósítása a STUN, DTLS, SCTP stb. valamint néhány kísérlet a QUIC-cal és a WebAssembly-vel. Ez a nyílt forráskódú könyvtár maga egy igazán jó tanulási forrás kiváló dokumentációval, hálózati protokoll-megvalósításokkal és remek példákkal.
A Pion közösség, amelyet egy nagyon szenvedélyes alkotó vezet, meglehetősen élénk, sok minőségi vita folyik a WebRTC-ről. Ha érdekel ez a technológia, csatlakozz http://pion.ly/slack – sok új dolgot fogsz megtanulni.
CloudRetro írása Golang nyelven
Munkavállaló megvalósítása a Go-ban
Irány a csatornák akcióban
A Go gyönyörű csatornakialakításának köszönhetően az események streamelésével és a párhuzamossággal kapcsolatos problémák jelentősen leegyszerűsödnek. Ahogy az ábrán is látható, a különböző GoRoutine-oknak több komponense fut párhuzamosan. Mindegyik komponens kezeli állapotát és csatornákon keresztül kommunikál. Golang szelektív állítása a játékban minden alkalommal egy atomi esemény feldolgozására kényszerít (játék pipa). Ez azt jelenti, hogy ehhez a kialakításhoz nincs szükség reteszelésre. Például amikor egy felhasználó ment, a játék állapotáról teljes pillanatfelvételre van szükség. Ennek az állapotnak folyamatosnak kell maradnia, be kell jelentkezni a mentés befejezéséig. Minden játék tick alatt a háttérprogram csak egy mentési vagy beviteli műveletet tud kezelni, így a folyamatszál biztonságossá válik.
func (e *gameEmulator) gameUpdate() {
for {
select {
case <-e.saveOperation:
e.saveGameState()
case key := <-e.input:
e.updateGameState(key)
case <-e.done:
e.close()
return
}
}
}
Fan-in/Fan-out
Ez a Golang-sablon tökéletesen illeszkedik a CrowdPlay és a Multiple Player használati eseteimhez. Ezt a mintát követve az összes felhasználói bemenet egy helyiségben a központi bejárati csatornába van beépítve. A játékmédia ezután ugyanabban a szobában lévő összes felhasználóhoz kerül. Ily módon elérjük a játék állapotának felosztását a különböző felhasználók több játékmenete között.
Szinkronizálás a különböző munkamenetek között
A Golang hátrányai
Golang nem tökéletes. A csatorna lassú. A blokkoláshoz képest a Go csatorna egyszerűen egyszerűbb módja az egyidejű és szálas események kezelésének, de a csatorna nem nyújtja a legjobb teljesítményt. A csatorna alatt összetett blokkoló logika található. Így néhány módosítást végeztem a megvalósításon, a teljesítmény optimalizálása érdekében újra alkalmaztam a zárakat és az atomértékeket a csatornák cseréjekor.
Ráadásul a golangi szemétgyűjtőt nem irányítják, ami néha gyanúsan hosszú szüneteket okoz. Ez nagymértékben zavarja a valós idejű streaming alkalmazást.
PATKÓSZEG
A projekt a meglévő nyílt forráskódú Golang VP8/H264 könyvtárat használja a médiatömörítéshez, a Libretrót pedig a játékemulátorokhoz. Mindezek a könyvtárak egyszerűen a C-könyvtár burkolói a Go-ban PATKÓSZEG. Néhány hátrányt felsorolunk ezt a bejegyzést írta Dave Cheney. Problémák, amelyekkel találkoztam:
képtelenség elkapni egy összeomlást a CGO-ban, még a Golang RecoveryCrash esetén sem;
a teljesítmény szűk keresztmetszetek azonosításának elmulasztása, amikor nem tudjuk észlelni a CGO részletes problémáit.
Következtetés
Elértem azt a célt, hogy megértsem a felhőalapú játékszolgáltatásokat, és létrehozzak egy olyan platformot, amely segít nosztalgikus retro játékokat játszani a barátaimmal online. Ez a projekt nem jöhetett volna létre a Pion könyvtár és a Pion közösség támogatása nélkül. Nagyon hálás vagyok az intenzív fejlesztésért. A WebRTC és a Pion által biztosított egyszerű API-k zökkenőmentes integrációt biztosítottak. Azon a héten adták ki az első proof of concept-emet, annak ellenére, hogy nem tudtam előzetesen a peer-to-peer (P2P) kommunikációt.
A könnyű integráció ellenére a P2P streaming valóban nagyon összetett terület a számítástechnikában. A peer-to-peer munkamenet létrehozásához meg kell küzdenie a régóta fennálló hálózati architektúrák, például az IP és a NAT összetettségével. A projekten való munkám során rengeteg értékes tudást szereztem a hálózatépítésről és a teljesítményoptimalizálásról, ezért arra biztatok mindenkit, hogy próbálja ki a WebRTC segítségével P2P termékek készítését.
A CloudRetro minden olyan használati esetet kielégít, amelyet retro játékosként vártam. Azonban úgy gondolom, hogy a projektben sok olyan terület van, amin javíthatok, mint például a hálózat megbízhatóbbá és teljesítményesebbé tétele, jobb minőségű játékgrafika biztosítása, vagy a játékok felhasználók közötti megosztásának lehetősége. Keményen dolgozom ezen. Kérlek kövess projekt és támogasd, ha tetszik.