WebRTC умеет работать Peer-to-Peer и Peer-to-Server, где в роли пира, как правило выступает браузер или мобильное приложение. В данной статье мы расскажем о работе WebRTC в режиме Server-to-Server, для чего это нужно и как это работает.
Масштабирование, Origin-Edge
Где может понадобиться межсерверное WebRTC? На ум сразу приходит паттерн Origin-Edge, который используется для масштабирования трансляции на большую аудиторию.
- Пользователь отправляет WebRTC видеопоток на Origin-WebRTC сервер с браузера или мобильного устройства.
- Origin-сервер рассылает поток по нескольким Edge-серверам.
- Edge-серверы раздают поток конечным пользователям на их браузеры и мобильные приложения.
В современных CDN для доставки видео активно используется протокол RTMP при публикации потока на Origin-сервер и при рассылке потока на Edge-сервера, а конечные пользователи получают картинку уже по HTTP.
Преимуществом WebRTC, по сравнению с данным подходом, может стать гарантированно низкая задержка трансляции, которой нельзя достичь средствами доставки RTMP / HTTP, особенно если ноды разнесены географически.
Однако для нас межсерверное WebRTC началось не с масштабирования.
Нагрузочные тесты
Они были всегда в том или ином виде. Автоматические и полуавтоматические, синтетические и близкие к тому, что делают пользователи. Мы использовали и используем нагрузочное тестирование для отлавливания многопоточных багов, контроля утечек ресурсов, оптимизаций, и многих других вещей, которые нельзя отловить на обычном тестировании.
На последних тестах мы поднимали Linux-серверы без GUI в облаке и запускали скрипты, стартующие много процессов браузера Google Chrome на виртуальном десктопе X11. Таким образом запускались реальные WebRTC-браузеры, которые тянули и играли WebRTC видеопотоки с Web Call Server, тем самым создавая нагрузку, максимально близкую к настоящей. Для сервера это выглядело так, словно реальный пользователь открывал браузер и забирал видеопоток, полностью задействуя WebRTC-стек браузера, включая декодинг и рендеринг видео.
Недостатком этого способа тестирования была производительность тестовой системы. Достаточно тяжело запустить много процессов Chrome на одной Linux-системе, даже при использовании мощного сервера с мегаметрами памяти и CPU. В результате приходилось поднимать много серверов и как-то ими управлять / мониторить.
Другим ограничением было отсутствие гибкости — мы не могли управлять процессами хрома. Было только две операции:
- Поднять процесс и открыть нужный урл
- Убить процесс.
При открытии урла подгружалась HTML страница и происходило автоматическое соединение с сервером, уже средствами JavaScript, Websocket + WebRTC. Так моделировалась зрительская нагрузка.
Требовался гибкий инструмент нагрузочного тестирования, который позволил бы давать нагрузку на сервер, близкую к реальной, контролировать тестирование программно и обеспечить высокую производительность тестирования.
Тестирование Server-Server
Мы пришли к выводу, что ноды нашего сервера сами могут стать генераторами нагрузки, если их правильно подцепить к тестируемым серверам.
Эта идея получила реализацию в виде WebRTC pulling. Один сервер WCS может вытянуть поток с другого сервера WCS по WebRTC. Для этого мы ввели внутреннюю абстракцию WebRTCAgent — объект, который поднимается на тестирующей ноде и тянет WebRTC-поток с тестируемой ноды, подключаясь к тестируемой ноде по Websocket+WebRTC.
После этого мы вынесли управление WebRTCAgent-ом на REST. В итоге нагрузочное тестирование свелось к вызову /pull — методов на REST интерфейсе тестирующей ноды.
При использовании межсерверного WebRTC нам удалось увеличить производительность нагрузочного тестирования примерно в 7 раз и значительно сократить использование ресурсов, по сравнению с той схемой, когда мы запускали процессы Google Chrome.
Итак, у нас получилось тянуть WebRTC-потоки с других серверов. Тестирующий сервер подключался к тестируемому по Websocket, и как порядочный браузер, устанавливал ICE-соединение, DTLS и тянул SRTP потоки на себя, — получился true WebRTC pulling.
Оставалась совсем немного для получения полноценной модели Origin-Edge. Для этого нужно было пробросить такой pulling в движок WCS сервера как публикуемый поток, т.е. сделать его похожим на поток с веб-камеры, а такие потоки WCS уже умеет раздавать по всем доступным протоколам: WebRTC, RTMP, RTMFP, Websocket Canvas, Websocket MSE, RTSP, HLS.
Origin-Edge на WebRTC
Получилось, что мы делали межсерверный WebRTC для нагрузочного тестирования, но в результате реализовали Origin-Edge схему для масштабирования WebRTC трансляций, и вот как она работает:
Зеленой линией показано как проходит видео трафик.
1. Пользователь из браузера или мобильного приложения, с помощью вебкамеры, отправляет WebRTC видеопоток с именем stream1 на сервер WCS1 — Origin. Процесс отправки видеопотока с помощью веб примера Two Way Streaming выглядит так:
А это JavaScript код, который отвечает за публикацию видеопотока через Web API (Web SDK):
session.createStream({name:'steram1',display:document.getElementById('myVideoDiv')}).publish();
2. Далее мы обращаемся к серверу WCS2 — Edge по REST/HTTP API и даем команду забрать видеопоток с Origin-сервера.
/rest-api/pull/startup { uri: wss://wcs1-origin.com:8443 remoteStreamName: stream1, localStreamName: stream1_edge, }
Сервер WCS2 подключается по вебсокетам к серверу WCS1 по адресу wss://wcs1-origin.com:8443 и принимает поток с именем stream1 по WebRTC.
После этого можно выполнить REST-команду
/rest-api/pull/find_all
чтобы вывести все текущие pull-подключения.
или команду
/rest-api/pull/terminate
чтобы закрыть pull-соединение с Origin WebRTC сервером.
3. И наконец, забираем поток с Edge-сервера по WebRTC в плеере. Вводим имя потока stream1_edge и начинаем его играть.
WCS — сервер поддерживает несколько способов воспроизведения. Чтобы поменять технологию, просто тащим вверх MSE или WSPlayer чтобы играть поток не по WebRTC, а по MSE (Media Source Extensions) или в WSPlayer (Websocket — плеер для iOS Safari).
Таким образом, схема Orign-Edge отработала и мы получили масштабируемость WebRTC-сервера с низкой задержкой.
Нужно заметить, что масштабируемость работала и раньше по RTMP. WCS сервер умеет делать ре-публикацию входящих WebRTC-потоков на один или несколько серверов по протоколу RTMP. В данном случае, поддержка межсерверного WebRTC стала шагом к снижению общей задержки системы.
И снова про нагрузочное тестирование
Для нормального нагрузочного тестирования осталось написать Web-интерфейс в виде REST-клиента, управляющего pull-сессиями. Этот интерфейс был назван Console и принял следующий вид:
С помощью консоли, можно тянуть отдельные WebRTC стримы, используя текущую ноду как Edge сервер.
Через этот же интерфейс можно добавить одну или несколько нод и запустить на них нагрузочные тесты с оценкой производительности.
Еще предстоит немало сделать и отдебажить. В частности интересно поработать с динамическими битрейтами на межсерверном WebRTC-канале и сравнить межсерверную проходимость с RTMP. Но уже сейчас у нас есть Orign-Edge на WebRTC и правильные нагрузочные тесты, дающие близкую к реальной нагрузку, что не может не радовать!
Ссылки
WCS5 — сервер Web Call Server 5, фигурирующий в статье
Two Way Streaming — пример трансляции видеопотока из браузера
WebRTC Player — пример воспроизведения видеопотока в браузере с возможностью смены технологий WebRTC, MSE, Flash, WSPlayer