Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност

Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
Софтуер като услуга, инфраструктура като услуга, платформа като услуга, комуникационна платформа като услуга, видеоконференции като услуга, а какво ще кажем за облачните игри като услуга? Вече имаше няколко опита за създаване на облачни игри (Cloud Gaming), например Stadia, наскоро стартирано от Google. Stadia не е новак в WebRTC, но могат ли и другите да използват WebRTC по същия начин?

Тхан Нгуен (Thanh Nguyen) реши да проверява тази възможност в своя опенсорсен проект CloudRetro. CloudRetro е базиран на Pion, популярна WebRTC библиотека, написана на Go (благодаря на Шон от екипа на Pion за помощта при подготовката на тази статия). В тази статия Тхан прави обзор на архитектурата на своя проект, както и споделя какво полезно е научил и с какви предизвикателства се е сблъскал по време на работата.

Въведение

Миналата година, когато Google обяви Stadia, буквално загубих ума си. Идеята е толкова уникална и иновативна, че постоянно си задавах въпроса как е възможно да се случи при съществуващите технологии. Желанието ми да разбера по-добре темата ме подтикна да създам своя версия на опенсорсна облачна игра. Резултатът беше просто фантастичен. По-долу бих искал да споделя процеса по работа върху моята годишна проект.

TLDR: кратка слайд версия с основните моменти

Защо облачните игри са бъдещето

Вярвам, че Cloud Gaming скоро ще стане новото поколение не само на игрите, но и на други области на информатиката. Облачните игри са върхът на клиент-сървър модела. Този модел максимизира контрола на бекенда и минимизира работата на фронтенда чрез разполагане на игровата логика на отдалечен сървър и стрийминг на изображения/аудио към клиента. Сървърът извършва тежката обработка, така че клиентът вече не зависи от хардуерните ограничения.

Google Stadia, по същество, позволява игра на AAA-игри (т.е. висококачествени игри-блокбастери) на интерфейс, подобен на YouTube. Същата методология може да се приложи и към други тежки оффлайн приложения, като операционна система или 2D/3D графичен дизайн и др., за да можем стабилно да ги стартираме на устройства с ниски технически характеристики на различни платформи.

Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
Бъдещето на тази технология: представете си, ако Microsoft Windows 10 работеше в браузъра Chrome?

Облачните игри са технически сложни.

Игрирането е една от тези редки области, където е необходима постоянна бърза реакция на потребителя. Ако случайно срещнем забавяне от 2 секунди при кликване на страницата, това е приемливо. Видеопотоковете на живо обикновено изостават с няколко секунди, но все пак предлагат достатъчно удобство за използване. Въпреки това, ако играта често забавя с 500 мс, играта просто става невъзможна. Целта ни е да постигнем изключително ниска латенция, за да намалим максимално разрива между входа и медията. Затова традиционният подход към видеострийминга тук не е приложим.

Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
Общ шаблон на облачната игра.

Отворен проект CloudRetro.

Реших да създам тестов образец на облачна игра, за да проверя, дали всичко е възможно при такива строги мрежови ограничения. За проверка на концепцията избрах Golang, тъй като е най-запознатият ми език и е подходящ за тази реализация по множество причини, как се оказа по-късно. Go е прост и се развива много бързо; каналите в Go са отлични за управление на многопоточността.

Проект CloudRetro.io – облачната игрова услуга с отворен код за ретро игри. Целта на проекта е да внесе в традиционните ретро игри най-комфортните игрови усещания и да добави мултиплейър.
Може да се запознаете с проекта тук: https://github.com/giongto35/cloud-game.

Функционалност на CloudRetro.

За демонстрация на цялата мощ на облачните игри в CloudRetro се използват ретро игри. Това позволява да се получат множество уникални игрови преживявания.

  • Портативност на играта.
    • Моментално възпроизвеждане при отваряне на страницата; не са нужни изтегляне и инсталиране.
    • Работи в мобилен браузър, така че няма нужда от никакъв софтуер за стартиране.

  • Игровите сесии могат да се споделят на различни устройства и да се съхраняват в облака за следващото влизане.
  • Играта може да се стриймва, а също така е възможно да се играе на нея веднага от много потребители:
    • Crowdplay тип TwitchPlayPokemon, само че по-кросплатформен и в реално време.
    • Офлайн игри онлайн. Могат да играят много потребители без настройки на мрежата. В Samurai Shodown сега могат да играят 2 играчи през облака CloudRetro.

    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Демо версия на многопользовательска онлайн игра на различни устройства

    Инфраструктура

    Изисквания и стек от технологии

    По-долу е списък на изискванията, които поставих преди началото на проекта.

    1. Един играч
    Това изискване може да изглежда не особено важно и очевидно тук, но е един от моите ключови изводи. То позволява на облачните игри да се отдалечат колкото се може повече от традиционните поточни услуги. Ако се фокусираме върху еднопотребителска игра, можем да се избавим от централизирания сървър или CDN, тъй като не е необходимо да предаваме потока на масите. Вместо да зареждаме потоци на поглъщащ сървър или да предаваме пакети на централизирания WebSocket сървър, сервисните потоци се предават директно на потребителя чрез P2P свързване с WebRTC.

    2. Медиен поток с ниска латентност
    Четейки за Stadia, често срещам в някои статии споменаване на WebRTC. Разбрах, че WebRTC е изключителна технология и е чудесно пригодена за използване в облачни игри. WebRTC е проект, който осигурява комуникация в реално време за уеб браузъри и мобилни приложения чрез прост API. Той предоставя P2P свързване, оптимизирано за медии и има вградени стандартни кодеци, като VP8 и H264.

    Дадох предпочитание на максимален комфорт за потребителите, вместо на запазване на високо качество на графиката. В алгоритъма са допустими определени загуби. В Google Stadia има допълнителна стъпка за намаляване на размера на изображението на сървъра, и кадрите се мащабират до по-високо качество преди предаване на P2P възлите.

    3. Разпределена инфраструктура с географска маршрутизация
    Независимо от того, колко оптимизиран е алгоритъмът за компресия и кодът, мрежата остава решаващият фактор, който най-много влияе на забавянето. Архитектурата трябва да има механизъм за свързване на най-близкия до потребителя сървър, за да се намали времето на предаване (RTT). Архитектурата трябва да разполага с 1 координатор и няколко стрийминг сървъра, разпределени по целия свят: Западен САЩ, Източен САЩ, Европа, Сингапур, Китай. Всички стрийминг сървъри трябва да бъдат напълно изолирани. Системата може да регулира своето разпределение, когато сървър се присъедини или изключи от мрежата. Така, при голям трафик, добавянето на допълнителни сървъри позволява извършване на хоризонтално мащабиране.

    4. Съвместимост на браузърите
    Облачните игри се представят най-добре, когато изискват минимално от потребителите. Това означава, че има възможност за стартиране в браузър. Браузърите помагат да се направи игровият процес възможно най-удобен за потребителите, освобождавайки ги от инсталирането на софтуер и хардуер. Браузърите също помагат да се осигури крос-платформеност за мобилни и десктоп версии. За щастие, WebRTC се поддържа много добре в различни браузъри.

    5. Ясно разделение на игровия интерфейс и услугата
    Виждам услугата за облачни игри като платформа. Всеки потребител трябва да има възможност да свърже каквото и да е към платформата. Сега интегрирах LibRetro с услугата за облачни игри, защото LibRetro предлага красив интерфейс на игровия емулятор за ретро игри, като SNES, GBA, PS.

    6. Стаи за мултиплейър, crowd play и дълбоко свързване (deep-link) с играта
    CloudRetro поддържа множество нови игрови формати, като CrowdPlay и Online MultiPlayer за ретро игри. Ако няколко потребители отворят един и същ deep-link на различни компютри, те ще видят същата активна игра и дори могат да се присъединят към нея.

    Освен това, състоянията на играта се съхраняват в облачно хранилище. Това позволява на потребителите да продължат играта по всяко време на всяко друго устройство.

    7. Хоризонтално мащабиране
    Както все SAAS в днешно време, облачните игри трябва да бъдат проектирани да бъдат хоризонтално мащабируеми. Дизайнът с "координатор-работник" позволява добавянето на повече работници, за да обслужват по-голям трафик.

    8. Няма обвързване с едно облако
    Инфраструктурата на CloudRetro е разположена при различни облачни доставчици (Digital Ocean, Alibaba, потребителски доставчик) за различни региони. Аз активирам старта в контейнер Docker за инфраструктурата и настройвам мрежовите параметри с помощта на bash скрипт, за да избегна зависимостта от един облачен доставчик. Комбинирайки това с NAT Traversal в WebRTC, можем да получим гъвкавост за разгръщане на CloudRetro на всяка облачна платформа и дори на машини на всеки потребител.

    Архитектурен дизайн

    Работник: (или потоков сървър, споменат по-горе) умножава игрите, стартира кодиращия пайплайн и предава кодираното медиа на потребителите. Инстанците на работника са разпределени по целия свят и всеки работник може да обработва множество потребителски сесии едновременно.

    Координатор: отговаря за свързването на нов потребител с най-подходящия работник за потоковата предаване. Координаторът взаимодейства с работниците чрез WebSocket.

    Хранилище на игровите състояния: централно отдалечено хранилище за всички игрови състояния. Това хранилище осигурява важни функции като отдалечено записване/зареждане.

    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Високо ниво архитектура на CloudRetro

    Потребителски сценарий

    Когато нов потребител отвори CloudRetro в стъпки 1 и 2, показани на изображението по-долу, координаторът заедно със списъка на наличните работници се запитва за първата страница. След това на стъпка 3 клиентът изчислява закъсненията за всички кандидати с помощта на HTTP заявка ping. Този списък със закъснения след това се изпраща обратно на координатора, за да може той да определи най-подходящия работник за обслужването на потребителя. На стъпка 4 по-долу се създава игра. Между потребителя и назначенния работник се установява потокова връзка WebRTC.
    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Потребителски сценарий след получаване на достъп

    Какво има вътре в работника

    Игровите и стрийминг пайплайни се съхраняват изолирано в работника и обменят информация през интерфейса. В момента тази свързаност се осъществява чрез предаване на данни в паметта по каналите на Golang в същия процес. Следващата цел е сегрегацията, т.е. независимото стартиране на игра в друг процес.

    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Взаимодействието на компонентите на работника

    Основни съставни части:

    • WebRTC: клиентски компонент, който приема вход от потребителя и излъчва кодирано медиа от сървъра.
    • Игрови емулатор: игрови компонент. Благодарение на библиотеката Libretro, системата може да стартира игра в един и същи процес и да прихваща медиа и входен поток отвътре.
    • Вътрешноигровите кадри се прихващат и изпращат към кодирача.
    • Изображение/аудио кодер: кодиращ пайплайн, който приема медиа кадри, кодира ги във фонов режим и излъчва кодирани изображения/аудио.

    Реализация

    CloudRetro разчита на WebRTC като основна технология, затова преди да навляза в подробности за имплементацията на Golang, реших да разкажа за самото WebRTC. Това е удивителна технология, която ми помогна значително да постигна забавяне на потока от данни, равно на само част от секундата.

    WebRTC

    WebRTC е предназначен да осигури висококачествени peer-to-peer връзки на нативни мобилни приложения и браузъри с помощта на прости API.

    NAT Traversal

    WebRTC е известен със своята функционалност NAT Traversal. WebRTC е предназначен за peer-to-peer комуникация. Целта му е да намери най-подходящия директен маршрут, избягвайки NAT шлюзове и防火墙и за peer-to-peer свързване чрез процес, наречен ICE. В рамките на този процес, API-то на WebRTC намира вашия публичен IP адрес с помощта на STUN сървъри и го пренасочва към сървър за реле (TURN), когато директна връзка не може да бъде установена.

    Въпреки това, CloudRetro не използва напълно тази възможност. Неговите peer-to-peer връзки не съществуват между потребителите, а между потребителите и облачните сървъри. Сървърната част на модела има по-малко ограничения за директна свързаност отколкото обикновеното потребителско устройство. Това позволява предварително отваряне на входящи портове или директна употреба на публични IP адреси, тъй като сървърът не е зад NAT.

    По-рано исках да превърна проекта в платформа за разпространение на игри за Cloud Gaming. Идеята беше да се позволи на създателите на игри да предоставят игри и стрийминг ресурси. Потребителите да взаимодействат директно с доставчиците. По този начин, в децентрализирана форма, CloudRetro е просто среда за свързване на странични стрийминг ресурси с потребителите, което го прави по-мащабируем, когато вече не носи хостинг. Ролята на WebRTC NAT Traversal е изключително важна за улесняване на инициализацията на peer-to-peer връзка на странични стрийминг ресурси, което опростява свързването на създателя с мрежата.

    Видео компресия

    Видео компресията е неизменна част от потока, която значително допринася за плавността на излъчването. Въпреки че не е необходимо да се знаят всички детайли по кодирането на видео в VP8/H264, разбирането на концепцията помага да се ориентираме в параметрите на скоростта на стрийминг видео, да се отстраняват неочаквани поведение и да се регулира закъснението.

    Компресията на видео за стрийминг услуга е сложна задача, тъй като алгоритъмът трябва да гарантира, че общото време за кодиране + време за предаване по мрежата + време за декодиране е толкова ниско, колкото е възможно. Освен това, процесът на кодиране трябва да бъде последователен и непрекъснат. Някои взаимни компромиси в кодирането не се прилагат – например, не можем да предпочетем дълго време за кодиране пред по-малък размер на файла и време за декодиране, или да използваме непоследователна компресия.

    Идеята за компресия на видео е да се премахнат ненужните битове информация, като се запази допустимото ниво на точност за потребителите. Освен кодирането на отделни статични кадри, алгоритъмът извежда текущия кадър от предишния и следващия, така че се предава само тяхната разлика. Както се вижда от примера с Pacman, предават се само диференциални точки.

    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Сравнение на видеокадри на примера с Pacman

    Аудио компресия

    По аналогичен начин, алгоритъмът за компресия на звук отпуска данни, които не могат да бъдат възприети от човека. Opus в момента е аудиокодек с най-добра производителност. Той е проектиран за предаване на звукови вълни чрез протокол за подредени пакетчета, такъв като RTP (Real Time Transport Protocol – протокол за пренос на реалновременен трафик). Задържането му е по-малко от това на mp3 и aac, а качеството е по-високо. Обикновено закъснението е около 5~66,5 мс.

    Pion, WebRTC в Golang

    Pion е проект с отворен код, който пренаписва WebRTC на Golang. Вместо да обвива обичайните нативни библиотеки на C++ WebRTC, Pion е нативна Golang реализация на WebRTC с по-добра производителност, интеграция с Go и управление на версиите на протоколите WebRTC.

    Библиотеката също така осигурява предаване на данни с множество отлични вградени модули с закъснение по-малко от секунда. Тя има своя реализация на STUN, DTLS, SCTP и др., и някои експерименти с QUIC и WebAssembly. Тази опенсорс библиотека сама по себе си е наистина добър източник на обучение с отлична документация, реализация на мрежови протоколи и страхотни примери.

    Обществото на Pion, ръководено от много запален създател, е доста активно, водят се много качествени дискусии относно WebRTC. Ако ви интересува тази технология, присъединете се към http://pion.ly/slack ще научите много нови неща.

    Написване на CloudRetro на Golang

    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Реализация на работник на Go

    Каналите на Go в действие

    Благодарение на красивия дизайн на каналите на Go, проблемите с поточно предаване на събития и паралелизъм значително се опростяват. Както е показано на диаграмата, в различни GoRoutines паралелно работят няколко компонента. Всеки компонент управлява собственото си състояние и комуникира чрез канали. Изборът на Golang налага обработването на едно атомарно събитие във всеки момент от времето в играта (game tick). Това означава, че за такъв дизайн не е необходимо блокиране. Например, когато потребителят запазва, необходим е пълен моментен snapshot на състоянието на играта. Това състояние трябва да остане непрекъснато, изпълнявайки входа, докато запазването не бъде завършено. По време на всеки game tick бекстендът може да обработва само операция на запазване или вход, което прави процеса потокобезопасен.

    func (e *gameEmulator) gameUpdate() {
    for {
    	select {
    		case <-e.saveOperation:
    			e.saveGameState()
    		case key := <-e.input:
    			e.updateGameState(key)
    		case <-e.done:
    			e.close()
    			return
    	}
        }
    }

    Фан-ин / Фан-аут

    Този Golang шаблон е идеален за моя сценарий на CrowdPlay и Multiple Player. Следвайки този шаблон, всички потребителски входове в една стая се вграждат в централен входен канал. Игралните медии след това се разпространяват на всички потребители в една стая. По този начин постигаме разделение на състоянието на играта между няколко игрови сесии на различни потребители.

    Облачни игри с отворен код на WebRTC: p2p, мултиплейър, нулева латентност
    Синхронизация между различни сесии

    Недостатъци на Golang

    Golang не е перфектен. Каналът е бавен. В сравнение с блокировките, каналите в Go предлагат просто по-лесен начин за обработка на паралелни и потокови събития, но каналът не осигурява най-добрата производителност. Под каналите има сложна логика на блокиране. Затова направих някои корекции в реализацията, повторно прилагайки блокировки и атомни стойности вместо каналите за оптимизиране на производителността.

    Освен това, garbage collector в Golang е неконтролиран, което понякога води до подозрително дълги паузи. Това значително пречи на работата на приложенията в реално време.

    CGO

    Проектът използва съществуваща VP8/H264 библиотека на Golang с отворен код за компресиране на медии и Libretro за игрови емулатори. Всички тези библиотеки просто обвиват C библиотеката в Go с използване на CGO. Някои от недостатъците са посочени в този пост на Dave Cheney. Проблемите, с които се сблъсквам:

    • невъзможността да уловим срив в CGO, дори с помощта на Golang RecoveryCrash;
    • невъзможността да определим узкото място в производителността, когато не можем да открием детайлни проблеми в CGO.

    Заключение

    Достигнах целта си – разбрах облачните игрови услуги и създадох платформа, която помага да играя носталгични ретро игри с приятелите ми онлайн. Създаването на този проект щеше да бъде невъзможно без библиотеката Pion и подкрепата на общността Pion. Изключително съм благодарен за интензивното му развитие. Простите API, предоставени от WebRTC и Pion, осигуриха гладка интеграция. Първото ми доказателство за концепция беше пуснато в същата седмица, въпреки че предварително не знаех за еднорогова връзка (P2P).

    Въпреки че интеграцията е проста, P2P стриймингът е наистина много сложна област в информатиката. Той се сблъсква със сложности, свързани с многогодишна мрежова архитектура, като IP и NAT, за създаване на пир(p2p)сесия. По време на работа по този проект натрупах много ценни знания за мрежите и оптимизацията на производителността, затова препоръчвам на всички да опитат да изградят P2P продукти с помощта на WebRTC.

    CloudRetro обслужва всички сценарии на използване, които очаквах като ретро-геймър. Въпреки това, смятам, че има много области в проекта, които мога да подобря, например, да направя мрежата по-надеждна и продуктивна, да осигуря по-високо качество на графиката на игрите или възможността за споделяне на игри между потребителите. Работя усърдно върху това. Моля, следете за проект и го подкрепете, ако ви харесва.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster