Последнее время в нашем блоге мы рассматриваем всевозможные варианты нагрузочных тестов. В одной из предыдущих статей мы тестировали один из распространённых сценариев работы сервера — «Один поток, много зрителей». В этом сценарии на сервере публикуется один WebRTC видеопоток и большое количество зрителей подключается для просмотра этого потока. Таким образом работает, например, трансляция соревнований: трансляция идет, пользователи смотрят. Но достаточно часто требуется реализовать другой подход — «Много потоков, много зрителей» — когда на сервере одновременно публикуется много WebRTC потоков и у каждого опубликованного потока есть один зритель. Такой вариант может использоваться для организации простого видеочата один на один без использования микшера или MCU.

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

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

  1. На тестирующем сервере WCS#1 опубликовать поток 1280×720, 30 fps, битрейт 2500 кбит/с
  2. Опубликовать исходный поток, при помощи REST API запроса /pull/push, в необходимом количестве экземпляров на тестируемый сервер WCS #2
  3. При помощи второго REST API запроса /pull/push забрать с тестируемого сервера WCS#2 на сервер WCS#1 каждый экземпляр ранее опубликованного потока
  4. На тестируемом сервере WCS#2 воспроизвести случайный поток и визуально оценить его качество. Оценить нагрузку на сервер с помощью метрик, получаемых от системы мониторинга Prometheus.

 

scheme-200-streams-720p-WCS-WebRTC-stream-WebSocket-publishing-testing-RESTApi

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

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

  • два WCS-сервера;
  • стандартный пример «Media Devices» для публикации потока с заданными параметрами;
  • скрипт для проведения теста;

 

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

Для тестирования мы использовали два сервера:

WCS#1 (тестирующий) с характеристиками:

  • 24 ядра, 48 потоков;
  • 128 Gb RAM;
  • WCS 5.2.946;
  • OpenJDK version 14.0.1

и

WCS#2 (тестируемый) с характеристиками:

  • 12 ядер, 24 потока;
  • 80 Gb RAM;
  • WCS 5.2.946;
  • OpenJDK version 14.0.1

 

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

Настройки наших серверов:

Файл flashphoner.properties (без настроек по умолчанию):

#webrtc ports range
media_port_from = 20001
media_port_to = 40000

wcs_activity_timer_timeout=86400000

global_bandwidth_check_enabled=true
zgc_log_parser_enable=true
zgc_log_time_format=yyyy-MM-dd'T'HH:mm:ss.SSSZ

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

Файл wcs-core.properties (без настроек по умолчанию):

-XX:ErrorFile=/usr/local/FlashphonerWebCallServer/logs/error%p.log

# ZGC
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms24g -Xmx24g -XX:+UseLargePages -XX:ZPath=/hugepages

-Xlog:gc*:/usr/local/FlashphonerWebCallServer/logs/gc-core-:time

Здесь мы изменили настройки для именования файлов логов, включили использование ZGC, настроили размер Heap и включили использование страниц памяти.

Полные версии файлов настроек можно скачать в разделе «Полезные файлы» в нижней части статьи. Там же вы найдете панель для Grafana и файл скрипта для запуска тестирования.

Скрипт для тестирования

#!/bin/bash

sourceStreamName=$1
sourceServer=$2
serverToTest=$3
testStreamsCount=$4

if [[ -z $sourceStreamName ]] || [[ -z $sourceServer ]] || [[ -z $serverToTest ]]; then
  echo "Usage: $(basename $0) stream_name source_server server_to_test test_streams_count"
  echo -e "   stream_name\t\tstream published on source server name"
  echo -e "   source_server\t\tsource server ip address"
  echo -e "   server_to_test\t\tserver to test ip address"
  echo -e "   test_streams_count\t\tstreams count to push (1 by default)"
  exit 1
fi

[[ -z $testStreamsCount ]] && testStreamsCount=1

# Check if source stream is published
result=`curl -s -i -o /dev/null -w '%{http_code}' -H "Content-Type: application/json" -X POST http://$sourceServer:8081/rest-api/stream/find --data "{\"name\":\"$sourceStreamName\",\"published\":true}" | grep 200`
if [[ $result != "200" ]]; then
  echo "Stream $sourceStreamName is not published on server $sourceServer!"
  exit 1
fi

# Push streams to the server to test
echo "Publishing $testStreamsCount copies of stream $sourceStreamName to the server $serverToTest"
for ((i = 1; i <= $testStreamsCount; i++)); do
  curl -s -H "Content-Type: application/json" -X POST http://$sourceServer:8081/rest-api/pull/push --data "{\"uri\":\"ws://$serverToTest:8080/websocket\",\"localStreamName\":\"$sourceStreamName\",\"remoteStreamName\":\"$sourceStreamName$i\"}"
done

# Wait for 5 seconds
echo "Waiting for 5 seconds..."
sleep 5

# Push streams back to source server
echo "Playing $testStreamsCount copies of stream $sourceStreamName from the server $serverToTest"
for ((i = 1; i <= $testStreamsCount; i++)); do
  curl -s -H "Content-Type: application/json" -X POST http://$serverToTest:8081/rest-api/pull/push --data "{\"uri\":\"ws://$sourceServer:8080/websocket\",\"localStreamName\":\"$sourceStreamName$i\",\"remoteStreamName\":\"$sourceStreamName$i\"}"
done

echo "To stop the test, just stop publishing stream $sourceStreamName"

где:

sourceStreamName — имя исходного потока, который опубликован на тестирующем сервере WCS#1;

sourceServer — Имя или IP адрес тестирующего сервера WCS#1;

serverToTest — Имя или IP адрес тестируемого сервера WCS#2;

testStreamsCount — количество потоков для теста.

Тестирование

На тестирующем сервере WCS#1 с помощью примера «Media Devices» опубликуем поток под именем «test» с параметрами 1280×720, 30 fps, битрейт 2500 кбит/с.

media-devices-720p-WCS-WebRTC-stream-WebSocket-publishing-testing-RESTApi

start-publish-media-devices-720p-WCS-WebRTC-stream-WebSocket-publishing-testing-RESTApi

Затем, в консоли тестирующего сервера, запускаем скрипт для тестирования со следующими параметрами:

./pull_push_test.sh test 172.16.40.3 172.16.40.2 200

где
test — имя опубликованного потока на WCS#1
172.16.40.3 — IP адрес тестирующего сервера WCS#1
172.16.40.2 — IP адрес тестируемого сервера WCS#2
200 — число потоков

Результат тестирования для 200 потоков на скриншоте ниже:

200-streams-720p-WCS-WebRTC-stream-WebSocket-publishing-testing-RESTApi

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

control-stream-720p-WCS-WebRTC-stream-WebSocket-publishing-testing-RESTApi

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

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

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

Полезные файлы

Панель для Grafana:

WebRTC-720p-testing.json

Настройки WCS:

flashphoner.properties

wcs-core.properties

Скрипт для теста:

pull_push_test.sh

Ссылки

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

WCS на Amazon EC2

WCS на DigitalOcean

WCS в Docker