Programvara som tjÀnst, infrastruktur som tjÀnst, plattform som tjÀnst, kommunikationsplattform som tjÀnst, videokonferenser som tjÀnst, men vad sÀgs om molngaming som tjÀnst? Det har redan gjorts flera försök att skapa molngaming (Cloud Gaming), som till exempel Stadia, nyligen lanserad av Google. Stadia , men kan andra anvÀnda WebRTC pÄ samma sÀtt?
Thanh Nguyen beslutade att undersöka denna möjlighet i sitt öppen kÀllkodsprojekt CloudRetro. CloudRetro Àr baserat pÄ Pion, WebRTC-bibliotek byggt pÄ Go (tack frÄn Pion-utvecklargruppen för hjÀlpen med att förbereda denna artikel). I denna artikel ger Thanh en översikt över arkitekturen av sitt projekt och berÀttar vad han har lÀrt sig och vilka utmaningar han har stött pÄ under arbetets gÄng.
Inledning
Förra Äret, nÀr Google tillkÀnnagav Stadia, blev jag helt exalterad. Idén Àr sÄ unik och innovativ att jag stÀndigt funderade pÄ hur nÄgot sÄdant överhuvudtaget Àr möjligt med de nuvarande teknologierna. En önskan att förstÄ detta bÀttre ledde mig till att skapa min egen version av molngaming med öppen kÀllkod. Resultatet var helt fantastiskt. Nedan vill jag dela med mig av processen bakom mitt ettÄriga .
TLDR: kort sammanfattning med huvudpunkterna
Varför molngaming Àr framtiden
Jag tror att molngaming snart kommer att bli den nya generationen av inte bara spel, utan Àven inom andra omrÄden av datavetenskap. Molngaming Àr toppen av klient/server-modellen. Denna modell maximerar backend-hantering och minimerar frontend-arbetet genom att placera spel-logiken pÄ en fjÀrrserver och streama bilder/ljud till klienten. Servern utför den tunga bearbetningen, sÄ klienten lÀngre Àr beroende av hÄrdvarubegrÀnsningar.
Google Stadia tillÄter i praktiken att spela (dvs. högklassiga blockbuster-spel) pÄ en plattform liknande YouTube. Samma metodik kan tillÀmpas pÄ andra tunga offline-applikationer, som operativsystem eller 2D/3D grafikdesign etc., sÄ att vi kan köra dem stabilt pÄ lÄgt specifikationsutrustning pÄ olika plattformar.

Framtiden för denna teknik: förestÀll dig att Microsoft Windows 10 skulle fungera i webblÀsaren Chrome?
Molnspel Àr tekniskt utmanande
Gaming Àr ett av de sÀllsynta omrÄdena dÀr konstant snabb respons frÄn anvÀndaren krÀvs. Om vi ibland har en fördröjning pÄ 2 sekunder nÀr vi klickar pÄ en sida, Àr det acceptabelt. Liveströmmar ligger vanligtvis efter med nÄgra sekunder, men erbjuder ÀndÄ tillrÀcklig anvÀndarvÀnlighet. Men om ett spel ofta laggar med 500 ms, Àr det helt enkelt omöjligt att spela. VÄrt mÄl Àr att uppnÄ extremt lÄg latens sÄ att skillnaden mellan input och media Àr sÄ liten som möjligt. DÀrför Àr den traditionella metoden för videostreaming hÀr inte tillÀmplig.

Den övergripande mallen för molnspel
Open source-projektet CloudRetro
Jag beslutade att skapa ett testexempel pÄ molnspel för att se om allt detta Àr möjligt under sÄdana strikta nÀtverksbegrÀnsningar. För konceptets test valde jag Golang eftersom det Àr det sprÄk jag Àr mest bekant med och passade vÀl för denna implementering av mÄnga andra skÀl, som senare visade sig. Go Àr enkelt och utvecklas vÀldigt snabbt; kanaler i Go Àr utmÀrkta för att hantera flertrÄdighet.
Projektet â en molnbaserad speltjĂ€nst med öppen kĂ€llkod för retrospel. Projektets mĂ„l Ă€r att ge traditionella retrospel en sĂ„ bekvĂ€m spelupplevelse som möjligt och att lĂ€gga till flerspelarlĂ€ge.
Du kan bekanta dig med projektet hÀr: .
Funktionalitet för CloudRetro
För att visa hela kraften i molnspel anvÀnds retrospel i CloudRetro. Detta gör att man kan fÄ en mÀngd unika spelupplevelser.
- Spelbarhet
- Omedelbar spelstart vid öppning av sidan; ingen nedladdning eller installation behövs
- Fungerar i mobilwebblÀsare, sÄ ingen programvara behövs för att köra det
- Spelsessioner kan delas mellan flera enheter och lagras i molnet för nÀsta inloggning
- Spelet kan streamas, och flera anvÀndare kan spela det direkt:
- Crowdplay à la TwitchPlayPokemon, bara mer plattformsövergripande och mer realtidsanpassat
- Offlinespel online. MÄnga anvÀndare kan spela utan nÀtverksinstÀllningar. I Samurai Shodown kan nu 2 spelare spela över CloudRetro-nÀtverket

Demoversion av ett flerspelarlÀge online-spel pÄ olika enheterInfrastruktur
Krav och teknologiska stackar
Nedanför finns en lista över krav som jag satte innan projektet startade.
1. En spelare
Detta krav kan verka oviktigt och uppenbart hÀr, men det Àr en av mina centrala insikter, det gör att molnspel kan hÄlla sig sÄ lÄngt borta frÄn traditionella strömningstjÀnster som möjligt. Om vi fokuserar pÄ enspelarlÀgen kan vi undvika behovet av en centraliserad server eller CDN, eftersom vi inte behöver sÀnda till massorna. IstÀllet för att ladda upp strömmar till en mottagande server eller skicka paket till en centraliserad WebSocket-server, överförs tjÀnstestreamar direkt till anvÀndarna genom en peer-to-peer WeRTC-anslutning.2. LÄg latens mediastreaming
NÀr jag lÀser om Stadia stöter jag ofta pÄ nÀmningar av WebRTC i vissa artiklar. Jag har förstÄtt att WebRTC Àr en lysande teknologi, och den passar perfekt för anvÀndning inom molnspel. WebRTC Àr ett projekt som erbjuder webblÀsare och mobilapplikationer realtidskommunikation via ett enkelt API. Det möjliggör en peer-to-peer-anslutning, optimerad för media och har inbyggda standardkodekar som VP8 och H264.Jag prioriterade att sÀkerstÀlla en sÄ bekvÀm anvÀndarupplevelse som möjligt, snarare Àn att bevara hög grafik. Vissa förluster Àr acceptabla i algoritmen. Google Stadia har ett extra steg för att minska bildstorleken pÄ servern, och bilderna skalas upp till högre kvalitet innan de överförs till peer-noder.
3. Distribuerad infrastruktur med geografisk routing
Oavsett hur optimerad komprimeringsalgoritmen och koden Àr, Àr nÀtverket fortfarande den avgörande faktorn som mest bidrar till latens. Arkitekturen mÄste ha en mekanism för att koppla ihop den server som Àr nÀrmast anvÀndaren för att minska överföringstiden (RTT). Arkitekturen bör ha en koordinator och flera streamingservrar spridda över hela vÀrlden: vÀstra USA, östra USA, Europa, Singapore, Kina. Alla streamingservrar mÄste vara helt isolerade. Systemet kan justera sin distribution nÀr en server gÄr med i nÀtverket eller lÀmnar det. PÄ sÄ sÀtt, vid hög trafik, gör ytterligare servrar det möjligt att utföra horisontell skalning.4. webblÀsarkompatibilitet
Molnspel framtrÀder i bÀsta ljus nÀr de krÀver minimalt av anvÀndarna. Detta betyder att det finns möjlighet att spela direkt i webblÀsaren. WebblÀsare hjÀlper till att göra spelupplevelsen sÄ bekvÀm som möjligt för anvÀndarna, utan att de behöver installera programvara eller hÄrdvara. WebblÀsare hjÀlper ocksÄ till att sÀkerstÀlla plattformsoberoende för mobila och desktopversioner. Lyckligtvis stöds WebRTC utmÀrkt i olika webblÀsare.5. Tydlig separation av spelgrÀnssnitt och tjÀnst
Jag betraktar molnspeltjÀnsten som en plattform. Varje anvÀndare ska kunna ansluta vad som helst till plattformen. Just nu har jag integrerat med molnspeltjÀnsten, eftersom LibRetro erbjuder ett vackert grÀnssnitt för spelemulatorer för retrospel som SNES, GBA, PS.6. Rum för flerspelare, crowd play och djup-lÀnkar (deep-link) till spelet
CloudRetro stöder mÄnga nya spelupplevelser, sÄsom CrowdPlay och Online Multiplayer för retrospel. Om flera anvÀndare öppnar samma djup-lÀnk pÄ olika datorer, kommer de att se samma pÄgÄende spel och till och med kunna gÄ med i det.Dessutom lagras spelens tillstÄnd i molnlagring. Detta gör att anvÀndare kan fortsÀtta spela nÀr som helst pÄ vilken annan enhet som helst.
7. Horisontell skalning
Precis som alla SAAS-tjÀnster mÄste molnspel idag utformas för att vara horisontellt skalbara. Designen "koordinator-arbetare" gör det möjligt att lÀgga till fler arbetare för att hantera högre trafik.8. Ingen bindning till ett enda moln
Infrastructure CloudRetro finns pÄ olika molnleverantörer (Digital Ocean, Alibaba, anpassad leverantör) för olika regioner. Jag aktiverar containerdrift med Docker för infrastrukturen och konfigurerar nÀtverksinstÀllningarna med hjÀlp av bash-skript för att undvika beroende av en enda molnleverantör. Genom att kombinera detta med NAT Traversal i WebRTC kan vi uppnÄ flexibilitet för att distribuera CloudRetro pÄ vilken molnplattform som helst och till och med pÄ anvÀndarmaskiner.Arkitekturdesign
Arbetare: (eller strömserver, som nÀmnts ovan) multiplicerar spelen, kör den kodande pipeline och överför den kodade media till anvÀndarna. Instanser av arbetaren Àr spridda över hela vÀrlden, och varje arbetare kan hantera flera anvÀndarsessioner samtidigt.
Koordinator: ansvarar för att koppla en ny anvÀndare till den mest lÀmpliga arbetaren för strömning. Koordinatorn interagerar med arbetarna via WebSocket.
Lagring av speltillstÄnd: ett centralt fjÀrrlager för alla spelets tillstÄnd. Detta lager tillhandahÄller viktiga funktioner, sÄsom fjÀrrspara/ladda.

Ăversiktlig arkitektur för CloudRetroAnvĂ€ndarscenario
NÀr en ny anvÀndare öppnar CloudRetro i steg 1 och 2, som visas nedan, begÀrs koordinatorn tillsammans med en lista över tillgÀngliga arbetare pÄ första sidan. DÀrefter, i steg 3, berÀknar klienten fördröjningarna för alla kandidater med hjÀlp av en HTTP ping-förfrÄgan. Denna lista med fördröjningar skickas sedan tillbaka till koordinatorn sÄ att denne kan avgöra den mest lÀmpliga arbetaren för att betjÀna anvÀndaren. I steg 4 nedan skapats ett spel. En strömförbindelse via WebRTC etableras mellan anvÀndaren och den tilldelade arbetaren.

AnvÀndarscenario efter ÄtkomstVad finns inuti arbetaren
Spel- och streamingspipeline lagras isolerat inom workern och utbyter information dÀr genom ett grÀnssnitt. För nÀrvarande sker denna koppling genom att överföra data i minnet via i samma process. NÀsta mÄl Àr segmentering, dvs. oberoende körning av spelet i en annan process.

Interaktionen mellan workerkomponenterHuvudkomponenter:
- WebRTC: klientkomponenten som tar emot anvÀndarinmatning och skickar kodad media frÄn servern.
- Spelemuator: spelskomponenten. Tack vare biblioteket Libretro kan systemet köra spelet inom samma process och internt fÄnga media och indataflöde.
- In-game frames fÄngas och skickas till kodaren.
- Bild-/ljudkodare: kodningspipeline som tar emot mediaprogram, kodar dem i bakgrunden och skickar ut kodade bilder/ljud.
Implementering
CloudRetro förlitar sig pÄ WebRTC som en huvudteknologi, sÄ innan jag dyker djupare in i implementeringen i Golang, ville jag berÀtta om sjÀlva WebRTC. Det Àr en fantastisk teknik som har hjÀlpt mig att uppnÄ en datastreamingfördröjning pÄ endast en brÄkdel av en sekund.
WebRTC
WebRTC Àr designat för att sÀkerstÀlla högkvalitativa peer-to-peer-anslutningar i inbyggda mobilapplikationer och webblÀsare med hjÀlp av enkla API:er.
NAT Traversal
WebRTC Àr kÀnt för sin funktionalitet NAT Traversal. WebRTC Àr avsett för peer-to-peer-kommunikation. Dess syfte Àr att hitta den mest lÀmpliga direkta vÀgen, undvika NAT-gateways och brandvÀggar för peer-to-peer-kommunikation genom en process som kallas . Inom ramen för denna process hittar WebRTC API din offentliga IP-adress med hjÀlp av STUN-servrar och omdirigerar den till en retransmission server (), nÀr en direkt anslutning inte kan etableras.
Men CloudRetro utnyttjar inte helt denna funktion. Dess peer-to-peer-anslutningar existerar inte mellan anvÀndare, utan mellan anvÀndare och molnservrar. Serverdelen av modellen har fÀrre begrÀnsningar för direkt kommunikation Àn vanliga anvÀndarenheter. Detta gör det möjligt att förhandsöppna inkommande portar eller anvÀnda offentliga IP-adresser direkt, eftersom servern inte ligger bakom NAT.
Tidigare ville jag förvandla projektet till en plattform för spridning av spel för Cloud Gaming. Idén var att lÄta spelutvecklare tillhandahÄlla spel och strömresurser. AnvÀndarna skulle interagera direkt med leverantörerna. I ett sÄdant decentraliserat format Àr CloudRetro bara en plattform för att koppla externa strömresurser till anvÀndarna, vilket gör det mer skalbart nÀr det inte lÀngre har hosting pÄ sig. Rollen av WebRTC NAT Traversal Àr mycket viktig för att underlÀtta initieringen av en peer-to-peer-anslutning pÄ externa strömresurser, vilket förenklar kopplingen av skaparen till nÀtverket.
Videokomprimering
Videokomprimering Ă€r en oumbĂ€rlig del av pipeline som i hög grad bidrar till smidigheten i strömningen. Ăven om det inte Ă€r nödvĂ€ndigt att kĂ€nna till alla detaljer om videokodning i VP8/H264, sĂ„ hjĂ€lper förstĂ„elsen av konceptet att hantera instĂ€llningarna för strömmande video, felsöka ovĂ€ntat beteende och justera latens.
Videokomprimering för en strömningstjĂ€nst Ă€r en komplex uppgift eftersom algoritmen mĂ„ste garantera att den totala kodningstiden + överföringstid + avkodningstid Ă€r sĂ„ liten som möjligt. Dessutom mĂ„ste kodningsprocessen vara konsekvent och kontinuerlig. Vissa ömsesidiga uppoffringar vid kodning Ă€r inte tillĂ€mpliga â till exempel kan vi inte föredra en lĂ„ng kodningstid framför en mindre filstorlek och avkodningstid, eller anvĂ€nda inkonsekvent komprimering.
Idén med videokomprimering Àr att utesluta onödiga bitar information och samtidigt behÄlla en acceptabel noggrannhetsnivÄ för anvÀndarna. Förutom att koda individuella stillbilder, gör algoritmen slutsatser för den aktuella bilden baserat pÄ föregÄende och nÀsta bild, sÄ att endast deras skillnader sÀnds. Som visas i exemplet med Pacman, skickas endast de differenspunkterna.

JÀmförelse av videobilder med Pacman-exempletLjudkomprimering
PĂ„ samma sĂ€tt hoppar ljudkomprimeringsalgoritmen över data som inte kan uppfattas av mĂ€nniskan. Opus Ă€r för nĂ€rvarande ljudkodeken med den bĂ€sta prestandan. Den Ă€r utformad för att skicka ljudvĂ„gor över protokoll för ordnad datagram, sĂ„som RTP (Real Time Transport Protocol â protokoll för realtidsöverföring av trafik). Den har lĂ€gre fördröjning Ă€n mp3 och aac, och kvaliteten Ă€r högre. Fördröjningen ligger vanligtvis runt 5~66,5 ms.
Pion, WebRTC i Golang
Àr ett open source-projekt som implementerar WebRTC i Golang. IstÀllet för att vanligtvis kapsla in native C++ WebRTC-bibliotek Àr Pion en nativ Golang-implementation av WebRTC med bÀttre prestanda, integration med Go och versionskontroll av WebRTC-protokoll.
Biblioteket erbjuder ocksÄ datastreaming med mÄnga utmÀrkta inbyggda moduler med en fördröjning pÄ mindre Àn en sekund. Det har sin egen implementation av STUN, DTLS, SCTP, etc., och vissa experiment med QUIC och WebAssembly. SjÀlva denna open source-bibliotek Àr verkligen en bra lÀrandekÀlla med utmÀrkt dokumentation, implementation av nÀtverksprotokoll och intressanta exempel.
Pion-communityt, lett av en mycket passionerad skapare, Ă€r ganska livligt, och det pĂ„gĂ„r mĂ„nga kvalitativa diskussioner om WebRTC. Om du Ă€r intresserad av den hĂ€r teknologin, gĂ„ med i â du kommer att lĂ€ra dig mycket nytt.
Att skriva CloudRetro i Golang

Implementering av en arbetsprocess i GoGo-kanaler i praktiken
Med den eleganta designen av Go-kanaler förenklas problem med hÀndelseströmning och parallellitet avsevÀrt. Som pÄ diagrammet arbetar flera komponenter parallellt i olika GoRoutines. Varje komponent hanterar sitt tillstÄnd och kommunicerar via kanaler. Go:s selektiva pÄstÄende tvingar varje atomÀr hÀndelse att hanteras vid varje given tidpunkt i spelet (game tick). Det betyder att en sÄdan design inte krÀver lÄsning. Till exempel, nÀr en anvÀndare sparar, krÀvs en fullstÀndig snapshot av spelets tillstÄnd. Detta tillstÄnd mÄste förbli kontinuerligt under inloggningen tills sparandet Àr slutfört. Under varje game tick kan backend endast bearbeta antingen sparande- eller inloggningsoperationer, vilket gör processen trÄdsÀker.
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
Denna Golang-mall passar perfekt för mitt anvÀndningsfall med CrowdPlay och flera spelare. Genom att följa denna mall samlas all anvÀndarinmatning i ett rum i en central ingÄngskanal. Spelmedia distribueras sedan till alla anvÀndare i rummet. PÄ sÄ sÀtt uppnÄr vi delning av speltillstÄnd mellan flera spel-sessioner av olika anvÀndare.

Synkronisering mellan olika sessionerNackdelar med Golang
Golang Àr inte perfekt. Kanaler Àr lÄngsamma. JÀmfört med lÄs Àr Go-kanaler ett enklare sÀtt att hantera parallella och strömmade hÀndelser, men kanalen ger inte den bÀsta prestandan. Under kanalen finns en komplicerad lÄslogik. DÀrför har jag gjort vissa justeringar i implementationen genom att ÄteranvÀnda lÄs och atomÀra vÀrden för att optimera prestanda.
Dessutom Àr garbage collectorn i Golang okontrollerad, vilket ibland leder till misstÀnkt lÄnga pauser. Detta stör starkt driften av realtidsapplikationer.
CGO
Projektet anvÀnder ett befintligt VP8/H264-bibliotek i Golang med öppen kÀllkod för komprimering av media och Libretro för spel-emulatorer. Alla dessa bibliotek Àr helt enkelt omslag av C-biblioteket i Go med anvÀndning av . NÄgra av nackdelarna Àr listade i . Problematiken jag stötte pÄ:
- oförmÄgan att fÄnga krascher i CGO, Àven med hjÀlp av Golang RecoveryCrash;
- oförmÄgan att identifiera flaskhalsar i prestanda nÀr vi inte kan upptÀcka detaljerade problem i CGO.
Slutsats
Jag har nĂ„tt mitt mĂ„l â att förstĂ„ molnbaserade speltjĂ€nster och skapa en plattform som hjĂ€lper mig att spela nostalgiska retrospel med mina vĂ€nner online. Att skapa detta projekt skulle vara omöjligt utan Pion-biblioteket och Pion-gemenskapens stöd. Jag Ă€r extremt tacksam för dess intensiva utveckling. De enkla API:erna som tillhandahĂ„lls av WebRTC och Pion möjliggjorde en smidig integration. Min första konceptbevis lanserades samma vecka, trots att jag pĂ„ förhand inte kĂ€nde till peer-to-peer-anslutningar (P2P).
Trots integrations enkelhet Àr P2P-strömning verkligen ett mycket komplext omrÄde inom datavetenskap. Det mÄste hantera komplexiteten i flerÄriga nÀtverksarkitekturer, sÄsom IP och NAT, för att skapa en peer-to-peer session. Under arbetet med detta projekt har jag samlat mycket vÀrdefull kunskap om nÀtverk och prestandaoptimering, sÄ jag rekommenderar alla att prova att bygga P2P-produkter med hjÀlp av WebRTC.
CloudRetro hanterar alla anvÀndningsscenarier som jag förvÀntade mig, utifrÄn min synvinkel som retro-gamer. Men jag tror att det finns mÄnga omrÄden i projektet som jag kan förbÀttra, sÄsom att göra nÀtverket mer pÄlitligt och effektivt, sÀkerstÀlla högre spelgrafik eller möjligheten att dela spel mellan anvÀndare. Jag arbetar hÄrt med detta. VÀnligen följ och stöd det om du gillar det.
KĂ€lla: habr.com







