Помните, как всего лишь несколько лет назад было обидно потерять фотоаппарат или камеру в конце отпуска? Все памятные кадры и видеоролики тогда исчезали вместе с утерянным устройством. Вероятно, именно этот факт подтолкнул великие умы к изобретению облачных хранилищ, чтобы сохранность записей больше не зависела от сохранности устройств, на которых эти записи сделаны.
Запись видеопотоков на стороне сервера во время стриминга кажется настолько естественной функцией, что многие наши пользователи даже не рассматривают ее как работу для сервера. Нередки такие утверждения от пользователей:
"У меня сервер в простое, только фоновая запись идет."
Но, если на сервере идет "только запись", значит, как минимум есть и видеопотоки, иначе что тогда записывать? Следовательно, не так уж и простаивает сервер. Да и сама запись все-таки расходует ресурсы некоторые ресурсы процессора и оперативной памяти. Также для хранения записей требуется выделить дисковое пространство — тут уже зависит от задачи: смотря сколько записей нужно хранить и в каком качестве.
Рассмотрим, как реализуется запись видео на стороне сервера на примере WCS. Браузер или мобильное приложение устанавливает соединение с WCS и отправляет WebRTC видеопоток. WCS записывает и сохраняет этот видеопоток в файловой системе сервера в виде файлов WebM или mp4, после чего эти записи доступны для скачивания и/или дальнейшей обработки. Например, можно переместить их в облачное хранилище Amazon S3.
MP4 для кодеков H.264 + AAC;
WebM для кодека VP8 + Vorbis
При одновременной записи большого количества публикаций сохранение файлов на диск по окончании записи может занимать существенное время. Поэтому, при выборе носителей для хранилища записей стоит обратить внимание не только на объем, но и на скорость работы (IOPS) и отдавать предпочтение наиболее быстрым вариантам.
Итак, задача — на вашем WCS сервере опубликовано 100 WebRTC стримов и вам нужно организовать их запись. Такой вариант работы может применяться для организации, например, системы видеонаблюдения, когда важно не только смотреть стрим в реальном времени, но и сохранить записи на случай каких-либо инцидентов. Исторически сложилось так, что в вашей инфраструктуре используются инстансы на AWS, большинство из которых это c5.4xlarge и инстанс для WCS не исключение. Решение по организации записи потоков не выглядит сложным — всего лишь одна REST команда для каждого потока и все работает. Но вдруг, спустя каких-то несколько минут после начала записи, на ваш телефон начинают сыпаться алармы от системы мониторинга — все плохо, все сломалось!
Итак, давайте проведем тесты и разберемся, почему такое могло произойти.
План тестирования
Опубликовать поток с камеры на сервере WCS #1;
С помощью веб-приложения Console забрать поток с сервера WCS#1 на WCS#2. При этом на сервере WCS#2 создается 100 входящих WebRTC потоков, которые будут записаны;
С помощью скрипта, использующего REST запросы, начать запись входящих на WCS#2 WebRTC потоков;
Выбрать случайный стрим на WCS#2 и визуально оценить деградацию потока (или ее отсутствие) во время работы записи потоков.
Остановить запись WebRTC потоков на WCS#2 с помощью скрипта, использующего REST запросы;
Оценить нагрузку на сервер WCS#2 по значениям метрик, собираемых системой мониторинга Prometheus для сервера WCS#2.
Тестирование будем считать успешным, если будут сформированы файлы записей и не будет зафиксировано деградации потоков в результатах мониторинга или визуально.
Подготовка к тестированию
Для тестирования записи мы использовали два AWS инстанса c5.4xlarge со следующими характеристиками:
16 vCPU;
32 Gb RAM;
10Gbps;
Web Call Server адаптирован для запуска в окружении Amazon EC2 в несколько кликов, так же можно и вручную развернуть WCS на инстансе Amazon EC2. После установки сервера мы немного оптимизировали настройки — включили ZGC и указали, сколько процессорных потоков использовать для работы рекордера:
file_recorder_thread_pool_max_size=8
Примеры файлов с настройками WCS — flashphoner.properties и wcs-core.properties можно скачать в разделе "Полезные файлы".
Инстанс WCS#2, на котором будет проводиться тестирование записи подключаем к мониторингу Prometheus+Grafana. В этом тестировании будем отслеживать следующие метрики
Загрузка процессора:
node_load1 node_load5 node_load15
Использование физической памяти для Java:
core_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="core_java_freePhysicalMemorySize"} core_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="core_java_totalPhysicalMemorySize"}
Паузы в работе ZGC:
gc_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="gc_last_pause_ms"}
Пропускная способность сети:
network_stats
Количество входящих WebRTC стримов:
streams_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="streams_webrtc_in"}
Количество и процент деградировавших стримов:
degraded_streams_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="degraded_streams"} degraded_streams_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="degraded_streams_percent"}
Количество открытых рекордеров (количество стримов для которых идет запись)
recording_stats{instance="your.WCS.server.name:8081", job="WCS_metrics_statistic", param="recording_sessions"}
Использование дискового пространства (в %)
100 - node_filesystem_avail_bytes{instance='your.WCS.server.name:9100' , fstype!='tmpfs'} / node_filesystem_size_bytes * 100
Готовую панель для Grafana можно скачать в разделе "Полезные файлы".
Тестирование
После завершения всех подготовительных работ приступаем к тестированию.
Потоки для записи создадим с помощью веб приложения Console:
На первом сервере WCS#1 откройте приложение Console через HTTP http://your.WCS.server.name:9091/client2/examples/demo/streaming/console/console.html
Укажите доменное имя или IP адрес первого сервера и нажмите кнопку «Add node». Это будет сервер источник WebRTC потока. Затем аналогично подключите к консоли второй WCS сервер, который будет захватывать потоки для записи.
Для первого сервера запустите стандартный пример Two-way Streaming и опубликуйте поток с веб камеры. Имя потока может быть любым.
4. В приложении Console выберите сервер WCS#2, нажмите кнопку "Pull streams" и задайте параметры захвата потоков:
Choose node — выберите первый сервер;
Local stream name — укажите имя потока на WCS#2 сервере в который будет захвачен поток от первого. (к имени потока будет добавлен индекс, соответствующий номеру захваченного потока). Указанное имя потока будет в дальнейшем использоваться в скрипте для записи потоков (у нас "Stream-");
Remote stream name — укажите имя опубликованного на первом сервере потока;
Qty — укажите количество зрителей (для нашего тестирования 100).
Нажмите кнопку "Pull" для запуска захвата потоков.
Запись захваченных потоков запускаем с помощью скрипта:
#!/bin/bash
qty=100
for i in `seq 1 $qty`; do
DATA='{"name":"Stream-'$i'", "published":true, "display":["metrics"]}'
curl --data "$DATA" -X POST -H "Content-Type: application/json" http://localhost:8081/rest-api/stream/find > stream.txt
mediaSession=`grep -P -o '(?<=\"mediaSessionId\"\:\").*(?=\"\,\"name\")' stream.txt`
DATA_rec='{"mediaSessionId":"'$mediaSession'", "config":{ }}'
curl --data "$DATA_rec" -X POST -H "Content-Type: application/json" http://localhost:8081/rest-api/stream/startRecording -nostdin -nostats </dev/null >/dev/null 2>&1 &
done
где:
qty - количество создаваемых рекордеров.
С помощью REST запроса /stream/find мы получаем список стримов, которые существуют на сервере, чтобы определить id медиасессии, затем запросом /stream/startRecording запускаем запись потока в соответствующей медиасессии.
Результат тестирования можно видеть на скриншоте:
Здесь можно заметить, что спустя около 15 минут после начала теста, файлы записей заняли 100% дискового пространства. По этой причине, не смотря на небольшую нагрузку на ресурсы сервера (Load average 1 в пике менее 8 единиц) и отсутствие деградировавших потоков, тест нельзя считать пройденным. Причина кроется в том, что для инстанса c5.4xlarge AWS предоставляет всего лишь 8 Гб дискового пространства. Поэтому достаточно большое число записей при тесте очень быстро его занимает полностью.
В первом тесте мы публиковали поток при помощи стандартного примера Two-way Streaming и поток был опубликован с параметрами 320x240, это достаточно "маленький" поток, который особо не нагружает сервер. Битрейт такого потока будет около 0,5 mbps. Создаваемый файл записи для одного такого потока занимает около 65 килобайт дискового пространства в секунду.
Давайте посмотрим, как поведет себя наш сервер, если мы опубликуем более "жирный" поток - 1080р (FullHD) со средним битрейтом 2,5 mbps. Для одного потока с такими параметрами прирост файла записи будет уже около 300 килобайт в секунду, что гораздо быстрее, чем для потока 240p.
Публикацию потока в этом случае запустим с помощью примера "Media Devices" где и зададим размеры кадра 1920х1080:
Затем запустим тест аналогично предыдущему. Результат теста на скриншоте ниже:
Тест с потоком 1080p ожидаемо показал результат аналогичный предыдущему тесту — записи снова заняли 100% доступного дискового пространства и поэтому продолжение работы сервера оказалось невозможным. В случае "большого" потока время в течении которого записи заняли все доступное место составило около 5 минут. Это в три раза быстрее, чем в предыдущем тесте с "маленьким" потоком. Итак, мы на практике убедились, что чем больше разрешение и битрейт потока, тем больше файлы записи занимают дискового пространства.
Немного изменим условия теста. В процессе тестирования будем останавливать запись и перемещать сформировавшиеся файлы записи. Результаты такого теста ниже:
Этот тест можно считать пройденным. Нагрузка на сервер была небольшой (Load Average 1 менее 8 единиц), деградировавших стримов не зафиксировано. В случае использования такого сценария работы следует учитывать, что при записи "больших" потоков, перемещать "кусочки" видео нужно чаще, чем для более "легких" потоков (с небольшим разрешением и битрейтом).
Для нарезки фрагментов записи не обязательно останавливать запись, как мы делали в тесте, можно воспользоваться функцией "Ротация файлов записей", которая настраивается при помощи параметра record_rotation в файле flashphoner.properties.
Например, настройка
record_rotation=20
определяет длительность фрагмента в 20 секунд, а настройка
record_rotation=10M
задает объем фрагмента в 10 мегабайт.
В итоге, можно сделать вывод, что инстанса c5.4xlarge достаточно для длительной записи 100 WebRTC потоков, при условии использования внешнего хранилища или дополнительного диска для записей.
Подтвердим последнее утверждение тестом. Повторим тест с подключенным к инстансу диском типа "st1" на 125 Гб. AWS заявляет для таких дисков производительность 500 IOPS, что в несколько раз больше, чем производительность SSD диска, который поставляется с инстансом по умолчанию.
За время теста было израсходовано около 5% емкости подключенного диска. Тест пройден успешно. Деградировавших стримов зафиксировано не было.
Таким образом, мы подтвердили утверждение, что инстанса c5.4xlarge достаточно для длительной записи 100 WebRTC потоков, при условии использования дополнительного диска для записей. В этом случае результаты теста меньше зависели от скорости работы процессорных потоков и оперативной памяти. Ключевой метрикой была скорость записи на диск и количество свободного дискового пространства. На вашем оборудовании при проведении вы можете получить другие результаты. Проще говоря, тест на мощных "железных" серверах покажет лучшие значения, чем тест на средних "виртуалках". Поэтому при проведении теста, нужно стараться создать окружение близкое к вашей реальной задаче.
Хорошего стриминга!
Полезные файлы
Панель для Grafana:
Настройки WCS:
Скрипты для теста:
Запуск записи:
Остановка записи:
Ссылки
WCS на Amazon EC2 - Быстрое развертывание WCS на базе Amazon
WCS на DigitalOcean - Быстрое развертывание WCS на базе DigitalOcean
WCS в Docker - Запуск WCS как Docker контейнера
Запись WebRTC видеопотока - Функция сервера для реализации записи видеопотоков для скачивания и дальнейшей обработки
Документация по быстрому развертыванию и тестированию WCS сервера
Документация по мониторингу информации о нагрузке и ресурсах
Документация по организации мониторинга с помощью Prometheus
Описание файла настроек flashphoner.properties
Описание файла настроек wcs-core.properties
Документация по управлению памятью в Java