Василий был доволен. Он наконец-то сдал работу заказчику и наслаждался свободным вечером. Позади осталась бездна часов разработки, оптимизации, тестирования, изменений и согласований.

И вот именно в тот момент, когда Василий был готов побаловать себя бутылочкой холодного пива, раздался звонок от заказчика.

«Подключиться к трансляции смогли только половина зрителей!» — услышал программист в телефонной трубке.

Печально вздохнув, он открыл ноутбук и начал изучать логи.

К сожалению, программист Василий не учел во время многочисленных тестов, что большое количество зрителей потребует большого количества ресурсов со стороны серверного железа и сети.

На самом деле Вася не одинок в своей беде, подобных вопросов в нашу техническую поддержку очень много:

«Какой мне нужен сервер для того, чтобы подключить 1000 зрителей?»

«У меня мощный сервер, но к трансляции подключаются только 250 подписчиков, а остальные или не могут подключиться, или получают потоки с ужасным качеством»

Эти вопросы объединяет одна тема — «Как выбрать правильный сервер?».

Раньше в нашем блоге мы уже обсуждали тему выбора сервера в зависимости от количества подписчиков. Кратко напомню основные тезисы:

1. При выборе серверов с балансировкой или без нее для потоковой передачи видео необходимо учитывать профили нагрузки:

  • просто стримы;
  • потоки с транскодированием;
  • микширование потоков.

 

2. Потоки с транскодированием и микшированием требуют больше ресурсов ЦП и ОЗУ, чем просто стримы. Нагрузка на системные ресурсы сервера не должна превышать 80%. В этом случае, все подписчики получат видеопотоки с приемлемым качеством.

3. На практике часто видно, что качество стриминга упирается не в характеристики сервера, а в пропускную способность сети.

Примерные расчеты количества стримов исходя из пропускной способности канала:

Один стрим 480p это примерно 0.5 — 1 Mbps трафика. Битрейт WebRTC потоков плавающий, поэтому возьмем 1 Mbps. Соответственно 1000 стримов — 1000 Mbps.

4. Количество зрителей и качество трансляции в том числе зависят от правильных настроек на стороне сервера — количества медиапортов и использования ZGC.

В этой статье мы рассмотрим, как провести нагрузочное тестирование сервера и на практике убедимся в справедливости утверждений выше.

План тестирования

scheme_сonnection_websocket_big_servers_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

  1. Опубликовать поток с камеры на сервере WCS #1 с помощью стандартного примера Two Way Streaming
  2. С помощью веб-приложение Console запустить нагрузочное тестирование, в котором сервер WCS#2 будет имитировать подключение 1000 зрителей к WCS#1.
  3. С помощью метрик, получаемых от системы мониторинга Prometheus, оценить нагрузку на сервер и количество исходящих WebRTC стримов от WCS#2.
  4. Если, при нагрузочном тестировании, сервер отправит заданное количество потоков визуально оценить деградацию потока (или ее отсутствие).

 

Будем считать тестирование успешным, если к WCS#1 удастся подключиться 1000 зрителей и при этом не будет видимой деградации потоков.

Подготовка к тестированию

Для тестирования нам понадобятся

  • два WCS-сервера;
  • стандартный пример Two-Way Streaming для публикации потока;
  • веб-приложение Console для проведения теста;
  • браузер Google Chrome и расширение Allow-Control-Allow-Origin для работы веб-приложения Console.

 

Если в вашем браузере не установлено расширение Access-Control-Allow-Origin, то установите его и запустите :

enable_CORS_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Предполагаем, что у вас уже есть установленный и настроенный экземпляр WCS. Если нет, то устанавливаем по этой инструкции.

Чтобы тестирование прошло успешно, и для того, чтобы оценить результаты, нужно выполнить следующие подготовительные этапы.

1. Увеличьте в файле flashphoner.properties диапазон портов для WebRTC подключений

media_port_from = 20001
media_port_to = 40000

При расширении диапазона медиапортов, проверьте, что диапазон не пересекается с другими портами, используемыми в работе сервера и диапазоном динамических портов Linux (при необходимости можно его изменить)

2. В том же файле укажите настройку, которая увеличивает время на прохождение теста и настройку, которая будет выводить на страницу статистики информацию о загруженности сети:

wcs_activity_timer_timeout=86400000
global_bandwidth_check_enabled=true

3. При большом количестве подписчиков на один поток (от 100 и более) и достаточных ресурсах процессора сервера и канала связи качество воспроизведения потока может падать: низкий FPS,могут появляться фризы. Что бы избежать такого поведения рекомендуется включить распределение доставки стримов подписчикам по процессорным потокам при помощи настройки в файле flashphoner.properties:

streaming_distributor_subgroup_enabled=true

В этом случае клиентские аудио и видео сессии будут распределяются по группам.

Максимальное количество видео сессий в группе задается настройкой:

streaming_distributor_subgroup_size=50

Максимальное количество аудио сессий в группе задается настройкой:

streaming_distributor_audio_subgroup_size=500

Размеры очередей пакетов на группу и максимальное время ожидания фрейма для отправки (в миллисекундах) задаются настройками:

streaming_distributor_subgroup_queue_size=300
streaming_distributor_subgroup_queue_max_waiting_time=5000
streaming_distributor_audio_subgroup_queue_size=300
streaming_distributor_audio_subgroup_queue_max_waiting_time=5000

4. Включить аппаратное ускорение шифрования WebRTC трафика. По умолчанию, для шифрования WebRTC трафика используется библиотека BouncyCastle, но, если процессор сервера поддерживает инструкции AES, целесообразно переключиться на использование Java Cryptography Extension при помощи настройки в файле flashphoner.properties

webrtc_aes_crypto_provider=JCE

и включить поддержку AES в настройках Java Virtual Machine в файле wcs-core.properties

-server
-XX:+UnlockDiagnosticVMOptions
-XX:+UseAES
-XX:+UseAESIntrinsics

В этом случае производительность шифрования за счет аппаратного ускорения увеличивается в 1,8-2 раза, что может снизить нагрузку на процессор сервера.

Проверить, поддерживает ли процессор сервера инструкции AES, можно при помощи команды:

lscpu | grep -o aes

5. Включите ZGC в JavaVM. Рекомендованные версии JDK, с которыми протестирована работа WCS, это 12 или 14 (Инструкция по установке).

Для настройки ZGC выполните следующие действия:

  • Нужно закомментировать в файле wcs-core.properties следующие строки:
-XX:+UseConcMarkSweepGC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=70
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
  • Поправить настройки для логов
-Xlog:gc*:/usr/local/FlashphonerWebCallServer/logs/gc-core.log
-XX:ErrorFile=/usr/local/FlashphonerWebCallServer/logs/error%p.log
  • Выставить размер хипа не менее, чем 1/2 физической памяти сервера
### JVM OPTIONS ###
-Xmx16g
-Xms16g
  • Включаем ZGC
# ZGC
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+UseLargePages -XX:ZPath=/hugepages
  • Настраиваем страницы памяти. Обязательно нужно рассчитать число страниц под размер выделенного хипа:
(1,125*heap_size*1024)/2. Для -Xmx16g это число (1,125*16*1024)/2=9216
mkdir /hugepages
echo "echo 9216 >/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages" >>/etc/rc.local
echo "mount -t hugetlbfs -o uid=0 nodev /hugepages" >>/etc/rc.local
chmod +x /etc/rc.d/rc.local
systemctl enable rc-local.service
systemctl restart rc-local.service

После выполнения настроек для ZGC нужно перезапустить WCS.

6. Для удобного отслеживания работы сервера во время тестирования предлагаем развернуть систему мониторинга Prometheus+Grafana.

Будем отслеживать следующие метрики:

  • Загрузка процессора:
node_load1
node_load5
node_load15
  • Использование физической памяти для Java:
core_stats{instance="your.WCS.server.name:8081", job="flashphoner", param="core_java_freePhysicalMemorySize"}
core_stats{instance="your.WCS.server.name:8081", job="flashphoner", param="core_java_totalPhysicalMemorySize"}
  • Паузы в работе ZGC:
custom_stats{instance="your.WCS.server.name:8081", job="flashphoner", param="gc_pause"}
  • Пропускная способность сети:
network_stats
  • Количество стримов. При нагрузочном тестировании будем считать исходящие WebRTC подключения:
streams_stats{instance="your.WCS.server.name:8081", job="flashphoner", param="streams_webrtc_out"}
  • Количество и процент деградировавших стримов:
degraded_streams_stats{instance="your.WCS.server.name:8081", job="flashphoner", param="degraded_streams"}
degraded_streams_stats{instance="your.WCS.server.name:8081", job="flashphoner", param="degraded_streams_percent"}

Тестирование первое — слабые серверы

Для первого тестирования будем использовать два сервера со следующими техническими характеристиками:

  • 1x Intel Atom C2550 @ 2.4Ghz (4 ядра, 4 потока);
  • 8GB RAM;
  • 2x 1Gbps

 

Пропускная способность канала заявлена как 2x 1Gbps. Давайте проверим, как это обстоит на самом деле.

Измерить пропускную способность канала можно при помощи утилиты iperf. Эта программа выпущена под все основные операционные системы: Windows, MacOS, Ubuntu/Debian, CentOS. iperf в режиме сервера может быть установлена вместе с WCS, что позволяет тестировать канал целиком, от паблишера до зрителя.

Запуск iperf в режиме сервера:

iperf3 -s -p 5201

здесь:
5201 — порт, на который iperf ожидает соединений от тестирующих клиентов.

Запуск iperf в режиме клиента для тестирования отправки данных от клиента к серверу по TCP:

iperf3 -c test.flashphoner.com -p 5201

здесь:
test.flashphoner.com — WCS сервер;
5201 — порт iperf в режиме сервера.

Устанавливаем и запускаем iperf в режиме сервера на первом сервере:

start_iperf_server_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Затем устанавливаем и запускаем iperf в режиме клиента на втором сервере и получаем данные о пропускной способности канала:

start_iperf_client_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Итак, между паблишером (первый север) и зрителем (второй сервер) ширина канала составляет в среднем 2.25 Gbps, а это значит, что, теоретически, мы можем подключить 2000 зрителей.

Теперь проверим это на практике.

Запустим нагрузочное тестирование.

На первом сервере откройте приложение Console через HTTP http://your.WCS.server.name:9091/client2/examples/demo/streaming/console/console.html

Укажите доменное имя или IP адрес первого сервера и нажмите кнопку «Add node». Это будет тестируемый сервер, который будет источником потоков. Затем аналогично подключите второй сервер, который будет имитировать подписчиков и захватывать потоки.

add_servers_to_console_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Для первого сервера запустите стандартный пример Two-way Streaming и опубликуйте поток с веб камеры. Имя потока может быть любым.

two-way_streaming_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

В приложении Console выберите сервер второй сервер, нажмите кнопку ‘Pull streams’, задайте параметры теста:

  • Choose node — выберите первый сервер;
  • Local stream name, Remote stream name — укажите имя опубликованного на первом сервере потока;
  • Qty — укажите количество зрителей (для нашего тестирования 1000)

 

После чего нажмите кнопку «Pull»:

pull_streams_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Во время тестирования будем отслеживать изменение метрик по графикам в Grafana:

dashboard_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Как видите, при тестировании возросла нагрузка на CPU сервера. Значение Load Averrage более 5 единиц для 4 ядерного процессора означает, что процессор загружен на 100%:

CPU_Averrage_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Уменьшилось количество свободной оперативной памяти:

Java_physical_memory_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Паузы для работы ZGC достигали 5 мс, что достаточно приемлемо:

ZGC_pause_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

График пропускной способности сетевого канала. Здесь мы видим, что основной трафик приходился на исходящие потоки. Скорость не превышала 100 Mbps (меньше 5% от заявленной пропускной способности, которую мы подтвердили тестом iperf ):

 

Число исходящих WebRTC стримов. Как видите, наше тестирование практически провалилось. За время тестирования нам не удалось отдать потоки больше, чем 260 пользователям из запрошенной 1000.

Global_bandwidth_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Деградировавшие стримы. Ближе к завершению тестирования появились деградировавшие потоки. Это вполне объяснимо, т.к. значение Load Averrage более 5 единиц для 4 ядерного процессора означает, что процессор загружен на 100% и деградация потоков в таких условиях неизбежна:

/degraded_streams_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Вывод к первому тестированию напрашивается сам собой:

Как бы не хотелось сэкономить на железе, но, к сожалению, слабый сервер, как и слабый виртуальный инстанс, не потянет серьезной нагрузки при использовании в продакшене. Хотя, если для вашей задачи не требуется подключать к потоку 1000 зрителей, то и этот вариант можно считать жизнеспособным.

Например, на «маленьком» сервере можно:

  • организовать простую систему видеонаблюдения — раздавать по WebRTC поток с IP-камеры небольшому количеству подписчиков;
  • организовать систему проведения вебинаров для сотрудников небольшой компании;
  • проводить трансляции только звука (аудиопоток требует меньше ресурсов процессора).

 

А теперь возьмем серверы помощнее и посмотрим, удастся ли подключить 1000 зрителей?

Тестирование второе — мощные серверы

Для второго тестирования будем использовать два сервера со следующими техническими характеристиками:

  • 2x Intel(R) Xeon(R) Silver 4214 CPU @ 2.20GHz (суммарно 24 ядра, 48 потоков);
  • 192GB RAM;
  • 2x 10Gbps

 

Как и в первом тестировании проверим пропускную способность канала между серверами с помощью iperf:

iperf_big_servers_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

В этом случае, между паблишером (первый сервер) и зрителем (второй сервер) ширина канала составила в среднем 9.42 Gbps, а это значит, что, теоретически, мы можем подключить 9000 зрителей.

Запустим нагрузочное тестирование точно так же, как и для первого тестирования с помощью веб приложения Console.

Отслеживаем изменение метрик по графикам в Grafana:

dashboard_big_servers_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Рассмотрим графики подробнее.

При запуске тестирования ожидаемо возросла нагрузка на CPU, но для 48 потоков процессора пиковое значение индекса Load Average чуть больше 11 единиц не сигнализирует о высокой нагрузке. Процессор сервера, конечно, работает, но до полной загрузки еще далеко:

CPU_Averrage_big_servers_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Количество свободной памяти ощутимо не изменялось:

Java_physical_memory_big_servers_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Паузы для работы ZGC достигали 2,5 мс, что достаточно приемлемо:

ZGC_pause_Grafana_big_servers_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

График пропускной способности сетевого канала. Здесь мы видим, что основной трафик приходился на исходящие потоки. Загрузка не превышала 500 Mbps (около 5% от заявленной пропускной способности, которую мы подтвердили тестом iperf ):

Global_bandwidth_big_servers_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Количество исходящих WebRTC стримов. Тестирование на мощных серверах завершилось успешно. Нам удалось подключить 1000 зрителей.

Connection_websocket_big_servers_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Деградировавшие стримы. Сервер успешно отработал, и деградировавших потоков за время тестирования не было:

degraded_stream_big_servers_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Для проверки успешности тестирования нужно в процессе тестирования подключиться к серверу и просмотреть стрим, так же как и подписчики, которых мы имитируем в тесте.

Открываем на тестируемом сервере плеер и воспроизводим наш тестовый стрим. Стрим должен проигрываться без видимой потери качества — без заиканий, фризов или артефактов:

play_stream_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Тестирование на мощных серверах можно считать успешным. Мы подключили 1001 зрителя на просмотр потока и отдали этот поток в приемлемом качестве.

Тестирование третье — мощные серверы, толстые потоки

В предыдущих двух тестах мы использовали в качестве потока источника небольшой поток с разрешением всего лишь 240p. Как показывает практика, такие потоки в современном мире мало кому интересны. Гораздо интереснее смотреть видео в формате от fullHD и выше. Итак, давайте проверим, справятся ли наши «большие» сервера с потоками 720p.

Для публикации потока нам понадобится пример «Media Devices» с помощью которого мы сможем опубликовать поток с заданными характеристиками:

media-devices_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Тест запустим прежним способом с помощью веб приложения Console. Результаты будем оценивать с помощью графиков в Grafana и контрольного воспроизведения опубликованного стрима.

В первом тесте прошло более 8 часов, прежде, чем смогли подключиться 1000 подписчиков, при этом по графикам видно, что нагрузка на сервер была совсем не большой:

1tester_dashboard_big_servers_720p_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Такое поведение прежде всего связано с мощностью тестирующего сервера, который захватывает потоки и имитирует подписчиков. В таком тестировании на тестирующий сервер тоже падает большая нагрузка, и, по всей видимости, сервер с ней не справился. Что бы проверить эту теорию добавим к условиям теста еще один тестирующий сервер, что бы разделить подписчиков и создаваемую ими нагрузку по 500 стримов на каждый сервер:

720p_scheme_сonnection_websocket_big_servers_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Запускаем тест точно так же как и в прошлых вариантах.

Теперь тест запустился гораздо быстрее. Менее чем через 10 минут от начала теста у нас уже было 1000 подписчиков:

dashboard_big_servers_720p_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Судя по графикам тест был пройден — загрузка процессора по метрике Load Average1 была в пределах 40 единиц. Единичный пик до 60 единиц не привел к снижению производительности. Паузы в работе ZGC не превышали 8 мс. Деградировавших стримов зарегистрировано не было. Воспроизведение публикуемого потока тоже прошло гладко — без фризов, артефактов и проблем со звуком.

play_stream_720p_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

Получается, что для успешного тестирования сервер, который будет захватывать потоки должен быть как минимум в два раза мощнее чем тестируемый сервер. Или можно использовать несколько серверов меньшей мощности.

Результаты тестирования могут меняться в зависимости от окружения, географического размещения серверов и пользователей — как подписчиков, так и стримеров.

В этой статье мы рассмотрели одну из методик проведения нагрузочного тестирования. По анализу результатов тестирования можно подобрать оптимальную конфигурацию сервера именно под вашу задачу, чтобы не допускать простоев или перегрузки оборудования.

Хорошего стриминга!

Ссылки

Наш демо сервер

WCS на Amazon EC2

WCS на DigitalOcean

WCS в Docker