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

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

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

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

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

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

«Какой мне нужен сервер для того, чтобы подключить 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. Включите 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.

4. Для удобного отслеживания работы сервера во время тестирования предлагаем развернуть систему мониторинга 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 Heap:

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 ):

Global_bandwidth_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

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

Connection_websocket_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 Averrage чуть больше 11 единиц не сигнализирует о высокой нагрузке. Процессор сервера, конечно, работает, но до полной загрузки еще далеко:

CPU_averrage_big_servers_Grafana_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

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

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

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

Например, выбираем имя стрима из списка в консоли:

console_choose_stream_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

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

play_stream_WCS_WebRTC_browser_stream_WebSocket_publishing_testing

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

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

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

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

Ссылки

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

WCS на Amazon EC2

WCS на DigitalOcean

WCS в Docker