Software as a Service, Infrastructure as a Service, Platform as a Service, Kommunikationsplattform als Dienst, Videokonferenzen als Dienst – und was ist mit Cloud-Gaming als Dienst? Es gab bereits mehrere Versuche, Cloud-Gaming zu entwickeln, wie beispielsweise Stadia, welches kürzlich von Google ins Leben gerufen wurde. ist kein Neuling in WebRTC, aber können andere WebRTC ebenso nutzen?
Thanh Nguyen hat beschlossen, diese Möglichkeit in seinem Open-Source-Projekt CloudRetro zu testen. CloudRetro basiert auf Pion, WebRTC-Bibliothek in Go (danke aus dem Pion-Entwicklerteam für die Unterstützung bei der Erstellung dieses Artikels). In diesem Artikel gibt Thanh einen Überblick über die Architektur seines Projekts und erzählt, welche wertvollen Erkenntnisse er gewonnen hat und mit welchen Herausforderungen er während der Arbeit konfrontiert war.
Einleitung
Im vergangenen Jahr, als Google Stadia ankündigte, war ich einfach überwältigt. Die Idee ist so einzigartig und innovativ, dass ich mich ständig fragte, wie so etwas mit der aktuellen Technologie möglich ist. Mein Wunsch, dieses Thema besser zu verstehen, motivierte mich dazu, meine eigene Version eines Open-Source-Cloud-Gaming-Dienstes zu entwickeln. Das Ergebnis war einfach fantastisch. Im Folgenden möchte ich den Prozess meiner einjährigen Arbeit teilen. .
TLDR: Eine kurze Zusammenfassung mit den Hauptpunkten
Warum Cloud Gaming die Zukunft hat
Ich bin überzeugt, dass Cloud Gaming bald nicht nur das kommende Zeitalter des Spielens, sondern auch anderer Informatikanwendungen einläuten wird. Cloud Gaming stellt das Höchstmaß eines Client/Server-Modells dar. Dieses Modell maximiert die Kontrolle über das Backend und minimiert die Anforderungen an das Frontend, indem die Spiel-Logik auf einem entfernten Server platziert und Bild-/Audiostreams an den Client übertragen werden. Der Server übernimmt die rechenintensive Verarbeitung, sodass der Client nicht mehr von Hardwarebeschränkungen abhängig ist.
Google Stadia ermöglicht es im Wesentlichen, AAA-Spiele zu spielen (d.h. hochkarätige Blockbuster-Spiele) auf einer Plattform ähnlich wie YouTube. Dieselbe Methodik kann auch auf andere ressourcenintensive Offline-Anwendungen angewendet werden, wie Betriebssysteme oder 2D/3D-Grafikdesign, damit wir sie stabil auf Geräten mit niedrigen technischen Spezifikationen auf verschiedenen Plattformen ausführen können.

Die Zukunft dieser Technologie: Stellen Sie sich vor, Microsoft Windows 10 würde im Browser Chrome laufen?
Cloud-Gaming ist technisch anspruchsvoll.
Gaming ist eines der wenigen Bereiche, in denen eine konstant schnelle Reaktion des Nutzers erforderlich ist. Wenn es gelegentlich eine Verzögerung von 2 Sekunden beim Klicken auf einer Seite gibt, ist das akzeptabel. Livestreams haben normalerweise ein paar Sekunden Verzögerung, bieten aber dennoch ausreichenden Nutzungskomfort. Wenn ein Spiel jedoch häufig um 500 ms verzögert ist, ist es einfach unmöglich zu spielen. Unser Ziel ist es, eine extrem niedrige Latenz zu erreichen, um die Lücke zwischen Eingabe und Medieninhalt so gering wie möglich zu halten. Daher ist der traditionelle Ansatz für Streaming-Videos hier nicht anwendbar.

Allgemeines Muster für Cloud-Gaming.
Open-Source-Projekt CloudRetro.
Ich habe beschlossen, ein Testmuster für Cloud-Gaming zu erstellen, um zu überprüfen, ob dies unter so strikten Netzwerkbedingungen möglich ist. Für den Konzeptnachweis habe ich Golang gewählt, da es die Sprache ist, mit der ich am vertrautesten bin, und sie aus vielen anderen Gründen gut für diese Umsetzung geeignet ist, wie sich später herausstellte. Go ist einfach und entwickelt sich sehr schnell; die Kanäle in Go eignen sich hervorragend zur Verwaltung von Parallelität.
Projekt – ein Cloud-Gaming-Service mit offener Quelle für Retro-Spiele. Ziel des Projekts ist es, den traditionellen Retro-Spielen das angenehmste Spielerlebnis zu verleihen und den Mehrspielermodus hinzuzufügen.
Hier können Sie das Projekt im Detail kennenlernen: .
Funktionalität von CloudRetro
Um die gesamte Kraft des Cloud-Gamings in CloudRetro zu demonstrieren, kommen Retro-Spiele zum Einsatz. Dadurch entstehen viele einzigartige Spielerlebnisse.
- Spielportabilität
- Sofortige Wiedergabe beim Öffnen der Seite; keine Downloads oder Installationen erforderlich.
- Funktioniert im mobilen Browser, sodass keine Softwareinstallation erforderlich ist.
- Spiele können auf mehreren Geräten gemeinsam genutzt und in der Cloud für den nächsten Login gespeichert werden.
- Das Spiel kann gestreamt oder von mehreren Benutzern gleichzeitig gespielt werden:
- Crowdplay wie bei TwitchPlayPokemon, jedoch plattformübergreifender und interaktiver.
- Offline-Spiele im Online-Modus. Viele Benutzer können ohne Netzwerkeinstellung spielen. In Samurai Shodown können jetzt 2 Spieler über CloudRetro online spielen.

Demo-Version eines Multiplayer-Onlinespiels auf verschiedenen Geräten.Infrastruktur
Anforderungen und Technologie-Stack
Im Folgenden finden Sie die Liste der Anforderungen, die ich vor Projektbeginn festgelegt habe.
1. Ein Spieler
Diese Anforderung mag hier nicht besonders wichtig oder offensichtlich erscheinen, aber sie ist eine meiner wichtigsten Erkenntnisse. Sie ermöglicht es Cloud-Gaming, sich von traditionellen Streaming-Diensten abzuwenden. Wenn wir uns auf Einzelspieler-Spiele konzentrieren, können wir auf zentrale Server oder CDN verzichten, da wir keine Massenübertragung durchführen müssen. Anstatt Streams auf einen zentralen Server zu laden oder Pakete an einen zentralen WebSocket-Server zu übertragen, werden die Dienst-Streams direkt über eine Peer-to-Peer-Verbindung mit WebRTC an den Benutzer gesendet.2. Niedriglatente Medienübertragung
Wenn ich über Stadia lese, stoße ich häufig in einigen Artikeln auf Erwähnungen von WebRTC. Mir wurde klar, dass WebRTC eine herausragende Technologie ist, die sich hervorragend für Cloud-Gaming eignet. WebRTC ist ein Projekt, das Webbrowsern und mobilen Anwendungen Echtzeitkommunikation über eine einfache API ermöglicht. Es bietet eine Peer-to-Peer-Verbindung, die für Medien optimiert ist und über integrierte Standardcodecs wie VP8 und H264 verfügt.Ich habe den Fokus auf die Schaffung einer möglichst komfortablen Nutzung für die Benutzer gelegt, anstatt die hohe Grafikqualität zu bewahren. Im Algorithmus sind einige Verluste zulässig. Google Stadia verfügt über einen zusätzlichen Schritt zur Reduzierung der Bildgröße auf dem Server, und die Frames werden in höherer Qualität skaliert, bevor sie an die Peer-to-Peer-Knoten übertragen werden.
3. Verteilte Infrastruktur mit geografischer Routenführung
Egal wie gut der Komprimierungsalgorithmus und der Code optimiert sind, das Netzwerk bleibt der entscheidende Faktor, der am meisten zur Latenz beiträgt. Die Architektur sollte einen Mechanismus zur Anbindung des nächstgelegenen Servers zum Benutzer haben, um die Round-Trip-Zeit (RTT) zu verkürzen. Sie sollte einen Koordinator und mehrere Streaming-Server weltweit umfassen: Westküste der USA, Ostküste der USA, Europa, Singapur, China. Alle Streaming-Server müssen vollständig isoliert sein. Das System kann seine Verteilung anpassen, wenn ein Server dem Netzwerk beitritt oder es verlässt. Auf diese Weise ermöglicht das Hinzufügen zusätzlicher Server bei hohem Verkehr horizontale Skalierung.4. Browserkompatibilität
Cloud-Gaming zeigt sein volles Potenzial, wenn es minimalen Aufwand von den Nutzern erfordert. Das bedeutet, dass die Spiele über den Browser gestartet werden können. Browser ermöglichen ein komfortableres Spielerlebnis, indem sie die Installation von Software und Hardware vermeiden. Zudem fördern sie die plattformübergreifende Nutzung für mobile und Desktop-Versionen. Glücklicherweise wird WebRTC in verschiedenen Browsern hervorragend unterstützt.5. Deutliche Trennung von Spieloberfläche und Dienst
Ich betrachte den Cloud-Gaming-Dienst als Plattform. Jeder sollte die Möglichkeit haben, beliebige Elemente an die Plattform anzuschließen. Aktuell habe ich in den Cloud-Gaming-Dienst integriert, da LibRetro eine ansprechende Schnittstelle für Emulatoren klassischer Spiele wie SNES, GBA und PS bietet.6. Räume für Mehrspieler, Crowd Play und Deep-Linking mit dem Spiel
CloudRetro unterstützt zahlreiche neue Spielmodi wie CrowdPlay und Online-Multiplayer für Retro-Spiele. Wenn mehrere Nutzer denselben Deep-Link auf unterschiedlichen Computern öffnen, sehen sie dasselbe laufende Spiel und können sogar daran teilnehmen.Außerdem werden die Spielstände in der Cloud gespeichert. Das ermöglicht es den Nutzern, jederzeit auf jedem anderen Gerät weiterzuspielen.
7. Horizontale Skalierung
Wie jede moderne SaaS-Lösung sollten Cloud-Games so konzipiert sein, dass sie horizontal skalierbar sind. Das Design mit „Koordinator-Arbeiter“-Modell erlaubt es, weitere Arbeiter hinzuzufügen, um größeren Traffic zu bewältigen.8. Keine Bindung an eine einzelne Cloud
Die Infrastruktur von CloudRetro wird über verschiedene Cloud-Anbieter (Digital Ocean, Alibaba, benutzerdefinierter Anbieter) in unterschiedlichen Regionen gehostet. Ich aktiviere das Deployment in einem Docker-Container für die Infrastruktur und konfiguriere die Netzwerkeinstellungen mit einem Bash-Skript, um die Abhängigkeit von einem einzelnen Cloud-Anbieter zu vermeiden. Durch die Kombination mit NAT Traversal in WebRTC erhalten wir die Flexibilität, CloudRetro auf jeder Cloud-Plattform und sogar auf den Maschinen von Nutzern bereitzustellen.Architekturdesign
Arbeiter: (oder Streaming-Server, wie oben erwähnt) vervielfacht Spiele, startet den Codierungs-Pipeline und überträgt codierte Medien an die Nutzer. Die Worker-Instanzen sind weltweit verteilt und jeder Worker kann mehrere Benutzersitzungen gleichzeitig verarbeiten.
Koordinator: verantwortlich für die Zuordnung neuer Benutzer zum am besten geeigneten Worker für das Streaming. Der Koordinator interagiert mit den Workern über WebSocket.
Speicher für Spielstände: eine zentrale Remote-Speicherlösung für alle Spielstände. Dieser Speicher bietet wichtige Funktionen wie Remote-Speicherung/Laden.

Übergeordnete Architektur von CloudRetroBenutzerszenario
Wenn ein neuer Benutzer CloudRetro in den Schritten 1 und 2 öffnet, wie im Bild unten gezeigt, wird der Koordinator zusammen mit der Liste der verfügbaren Worker an die erste Seite angefragt. Danach berechnet der Kunde in Schritt 3 die Latenzen für alle Kandidaten mithilfe einer HTTP-Ping-Anfrage. Diese Liste der Latenzen wird dann zurück an den Koordinator gesendet, damit dieser den geeignetsten Worker zur Betreuung des Benutzers bestimmen kann. In Schritt 4 wird das Spiel erstellt. Eine Streaming-Verbindung über WebRTC wird zwischen dem Benutzer und dem zugewiesenen Worker eingerichtet.

Benutzerszenario nach Erhalt des ZugriffsWas sich im Worker befindet
Die Spiel- und Streaming-Pipelines werden isoliert im Worker gespeichert und tauschen dort Informationen über Schnittstellen aus. Derzeit geschieht diese Verbindung über die Speicherübertragung über im selben Prozess. Das nächste Ziel ist die Segregation, d.h. das unabhängige Ausführen des Spiels in einem anderen Prozess.

Interaktion der Worker-KomponentenDie Hauptkomponenten:
- WebRTC: Client-Komponente, die Benutzereingaben annimmt und codierte Medien vom Server ausgibt.
- Gaming-Emulator: Gaming-Komponente. Dank der Libretro-Bibliothek kann das System das Spiel innerhalb desselben Prozesses starten und Medien sowie Eingabeströme intern abfangen.
- In-Game-Bilder werden erfasst und an den Encoder gesendet.
- Bild-/Audio-Encoder: Codierpipeline, die Mediendatenpakete entgegennimmt, sie im Hintergrund codiert und die codierten Bilder/Audios ausgibt.
Implementierung
CloudRetro nutzt WebRTC als zugrunde liegende Technologie, daher wollte ich, bevor ich in die Details der Implementierung in Golang eintauche, über WebRTC selbst sprechen. Es ist eine erstaunliche Technologie, die mir sehr geholfen hat, eine Übertragungsverzögerung von nur einem Bruchteil einer Sekunde zu erreichen.
WebRTC
WebRTC ist darauf ausgelegt, qualitativ hochwertige Peer-to-Peer-Verbindungen auf nativen mobilen Anwendungen und in Browsern über einfache APIs bereitzustellen.
NAT Traversal
WebRTC ist bekannt für seine NAT-Traversal-Funktionalität. WebRTC ist für Peer-to-Peer-Kommunikation konzipiert. Sein Ziel ist es, den am besten geeigneten direkten Weg zu finden und NAT-Gateways und Firewalls für Peer-to-Peer-Verbindungen zu vermeiden, durch einen Prozess namens . Im Rahmen dieses Prozesses ermittelt die WebRTC-API Ihre öffentliche IP-Adresse über STUN-Server und leitet sie an den Relay-Server weiter (), wenn eine direkte Verbindung nicht hergestellt werden kann.
CloudRetro nutzt jedoch diese Möglichkeit nicht vollständig. Dessen Peer-to-Peer-Verbindungen bestehen nicht zwischen Benutzern, sondern zwischen Benutzern und Cloud-Servern. Die Serverseite des Modells hat weniger Einschränkungen bei der direkten Kommunikation als gewöhnliche Benutzergeräte. Dies ermöglicht das vorzeitige Öffnen eingehender Ports oder die direkte Nutzung öffentlicher IP-Adressen, da der Server nicht hinter einem NAT sitzt.
Früher wollte ich das Projekt in eine Plattform für Cloud-Gaming-Verbreitung verwandeln. Die Idee war, es Spieleentwicklern zu ermöglichen, Spiele und Streaming-Ressourcen anzubieten, während die Nutzer direkt mit den Anbietern interagieren. In diesem dezentralisierten Ansatz fungiert CloudRetro lediglich als Schnittstelle, um externe Streaming-Ressourcen mit den Nutzern zu verbinden, was es skalierbarer macht, da der Hosting-Betrieb entfällt. Die Rolle des WebRTC NAT Traversal ist hier entscheidend, um die Initiierung von Peer-to-Peer-Verbindungen zu externen Streaming-Ressourcen zu erleichtern, wodurch die Verbindung zwischen dem Entwickler und dem Netzwerk vereinfacht wird.
Video-Kompression
Die Video-Kompression ist ein unerlässlicher Teil des Workflows, der erheblich zur Flüssigkeit des Streams beiträgt. Auch wenn es nicht notwendig ist, alle Details der Video-Codierung in VP8/H264 zu kennen, hilft ein Verständnis des Konzepts, die Streaming-Video-Bitrate einzuschätzen, unerwartetes Verhalten zu beheben und die Latenz zu optimieren.
Die Video-Kompression für Streaming-Dienste stellt eine komplexe Herausforderung dar, da der Algorithmus sicherstellen muss, dass die gesamte Kodierungszeit + die Netzwerkübertragungszeit + die Dekodierungszeit so gering wie möglich ist. Darüber hinaus muss der Kodierungsprozess kontinuierlich und konsistent sein. Bestimmte Kompromisse bei der Kodierung sind nicht anwendbar – beispielsweise können wir nicht eine längere Kodierungszeit einem kleinere Dateigröße und Dekodierungszeit vorziehen oder inkonsistente Kompression verwenden.
Die Idee der Video-Kompression besteht darin, unnötige Informationsbits zu entfernen und gleichzeitig ein akzeptables Genauigkeitsniveau für die Benutzer beizubehalten. Neben der Kodierung einzelner statischer Bildrahmen zieht der Algorithmus Schlussfolgerungen für den aktuellen Rahmen aus dem vorherigen und dem nächsten, sodass nur deren Unterschiede übertragen werden. Wie im Beispiel mit Pacman zu sehen ist, werden nur differenzielle Punkte übertragen.

Vergleich von Videorahmen am Beispiel PacmanAudio-Kompression
Ebenso lässt der Audiokomprimierungsalgorithmus Daten weg, die vom Menschen nicht wahrgenommen werden können. Opus ist derzeit der leistungsfähigste Audiocodec. Er wurde entwickelt, um Audiosignale über ein Protokoll für geordnete Datagramme wie RTP (Real Time Transport Protocol – Protokoll für die Übertragung von Echtzeitdaten) zu übertragen. Seine Latenz ist geringer als die von mp3 und aac, während die Qualität höher ist. Die Latenz beträgt normalerweise etwa 5 bis 66,5 ms.
Pion, WebRTC in Golang
ist ein Open-Source-Projekt, das WebRTC nach Golang portiert. Anstelle des üblichen Wrappers für native C++-Bibliotheken von WebRTC ist Pion eine native Golang-Implementierung von WebRTC mit besserer Leistung, Integration in Go und Versionierung auf den Protokollen von WebRTC.
Die Bibliothek bietet auch Streaming mit zahlreichen großartigen integrierten Modulen mit einer Latenz von weniger als einer Sekunde. Sie verfügt über eine eigene Implementierung von STUN, DTLS, SCTP usw. sowie einige Experimente mit QUIC und WebAssembly. Diese Open-Source-Bibliothek ist selbst ein wirklich guter Lernort mit hervorragender Dokumentation, Implementierung von Netzwerkprotokollen und tollen Beispielen.
Die Pion-Community, geleitet von einem sehr leidenschaftlichen Entwickler, ist ziemlich lebhaft und es finden viele qualitativ hochwertige Diskussionen über WebRTC statt. Wenn Sie an dieser Technologie interessiert sind, schließen Sie sich uns an, – Sie werden viel Neues lernen.
CloudRetro in Golang schreiben

Implementierung eines Workers in GoGo-Kanäle in Aktion
Durch das ansprechende Design der Go-Kanäle werden Herausforderungen bei der Streaming-Übertragung von Ereignissen und Parallelität erheblich reduziert. Wie in der Grafik dargestellt, arbeiten mehrere Komponenten in verschiedenen GoRoutinen parallel. Jede Komponente verwaltet ihren eigenen Zustand und kommuniziert über Kanäle. Die selektive Aussage in Golang zwingt dazu, jedes atomare Ereignis zu einem bestimmten Zeitpunkt im Spiel (game tick) zu verarbeiten. Das bedeutet, dass für dieses Design keine Sperren erforderlich sind. Wenn zum Beispiel ein Benutzer speichert, ist ein kompletter Snapshot des Spielzustands erforderlich. Dieser Zustand muss konstant bleiben, während Eingaben weiter verarbeitet werden, bis der Speicherprozess abgeschlossen ist. Während jedes game tick kann das Backend nur die Speicher- oder Eingabefunktion verarbeiten, was den Prozess thread-sicher macht.
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
Diese Golang-Vorlage eignet sich hervorragend für mein Nutzungsszenario mit CrowdPlay und mehreren Spielern. Mit dieser Vorlage werden alle Benutzereingaben in einem Raum in einen zentralen Eingabekanal integriert. Die Spielmedien werden dann an alle Benutzer in diesem Raum verteilt. So erreichen wir eine Trennung des Spielstatus zwischen mehreren Spielsitzungen verschiedener Benutzer.

Synchronisation zwischen verschiedenen SitzungenNachteile von Golang
Golang ist nicht perfekt. Der Kanal ist langsam. Im Vergleich zu Kanälen ist Go lediglich eine einfachere Methode zur Handhabung paralleler und streamender Ereignisse, jedoch bietet der Kanal nicht die beste Leistung. Unter dem Kanal liegt eine komplexe Logik zur Blockierung. Daher habe ich einige Anpassungen an der Implementierung vorgenommen, indem ich Sperren und atomare Werte wiederverwendet habe, um die Leistung zu optimieren.
Darüber hinaus ist der Garbage Collector in Golang nicht verwaltbar, was gelegentlich zu verdächtig langen Pausen führt. Dies beeinträchtigt die Leistung einer Echtzeitanwendung erheblich.
CGO
Im Projekt wird die vorhandene VP8/H264 Golang-Bibliothek mit Open Source verwendet, um Medien zu komprimieren, sowie Libretro für Spieleemulatoren. Alle diese Bibliotheken sind lediglich Wrapper der C-Bibliothek in Go, die verwendet werden. . Einige der Nachteile werden in aufgeführt. Die Herausforderungen, mit denen ich konfrontiert war:
- die Unfähigkeit, Abstürze in CGO abzufangen, selbst mit Golang RecoveryCrash;
- die Unfähigkeit, Engpässe in der Leistung zu identifizieren, wenn wir detaillierte Probleme in CGO nicht erkennen können.
Fazit
Ich habe mein Ziel erreicht – ich habe mich in cloudbasierte Spieleservices eingearbeitet und eine Plattform geschaffen, die es mir ermöglicht, nostalgische Retro-Spiele online mit meinen Freunden zu spielen. Die Erstellung dieses Projekts wäre ohne die Pion-Bibliothek und die Unterstützung der Pion-Community unmöglich gewesen. Ich bin äußerst dankbar für die intensive Entwicklung. Die einfachen APIs, die von WebRTC und Pion bereitgestellt werden, haben eine reibungslose Integration ermöglicht. Mein erstes Konzept wurde noch in derselben Woche veröffentlicht, obwohl ich im Voraus nichts über die Peer-to-Peer-Verbindung (P2P) wusste.
Trotz der einfachen Integration ist P2P-Streaming ein äußerst komplexes Thema in der Informatik. Es erfordert die Auseinandersetzung mit den Herausforderungen jahrzehntelanger Netzwerkarchitekturen wie IP und NAT, um eine Peer-to-Peer-Sitzung zu etablieren. Während der Arbeit an diesem Projekt habe ich viele wertvolle Erkenntnisse über Netzwerke und Leistungsoptimierung gesammelt, weshalb ich jedem empfehle, P2P-Produkte mit WebRTC zu entwickeln.
CloudRetro unterstützt alle Nutzungsszenarien, die ich als Retro-Gamer erwartet habe. Dennoch glaube ich, dass es viele Bereiche im Projekt gibt, die ich verbessern kann, zum Beispiel die Zuverlässigkeit und Leistungsfähigkeit des Netzwerks, die Grafikqualität der Spiele oder die Möglichkeit, Spiele unter den Nutzern zu teilen. Ich arbeite intensiv daran. Bitte bleiben Sie dran, und unterstützen Sie es, wenn es Ihnen gefällt.
Quelle: habr.com







