Групповые звонки при масштабировании: 50, 500, 5000 участников

Автор: Николай СапуновОбновлено: август 202621 мин чтения
Содержание статьи +

Кратко

Групповой звонок, отлично работающий на десяти участниках, может начать сбоить при пятидесяти, упасть при пятистах и превратиться в принципиально иную систему при пяти тысячах – и чаще всего первыми ломаются именно аудио, а не видео. Причина проста и арифметична: если каждый микрофон транслируется каждому слушателю, объём нагрузки растёт пропорционально квадрату числа участников, поэтому удвоение количества пользователей примерно учетверяет нагрузку. Решение – перестать одинаково обрабатывать все голоса: передавать только тех, кто действительно говорит, а на самых больших масштабах ещё и смешивать их на сервере в один общий поток, чтобы каждый слушатель по-прежнему получал лишь один аудиоканал. Эта статья рассматривает три режима работы: маленькая комната, где передаются все голоса; большая комната, где передаются только активные говорящие; и массовая трансляция, где голоса смешиваются и раздаются как единый поток. В ней приведены цифры, чтобы понять, в каком режиме работает ваш продукт.

Почему это важно

Если вы планируете виртуальный класс, инструмент для корпоративных собраний, вебинар-таунхолл, лайв-шопинг или экстренную связь, то число, которое вы укажете в поле «максимальное количество участников» в спецификации продукта, незаметно определяет всю вашу аудиоархитектуру и счёт за серверы. Команды часто проектируют систему под демо – скажем, двенадцать человек в видеосетке – а потом обнаруживают, что собрание на 300 человек либо перегружает сервер, либо звучит как стадион. Эта статья предназначена для продакт-менеджера, основателя или технического лидера, которому важно понять, почему стоимость аудио резко растёт с масштабом и что меняется на каждом пороге числа участников, чтобы честно оценить инфраструктуру и задать инженерам правильные вопросы до запуска, а не во время сбоя. Старший инженер найдёт здесь каждое утверждение с ссылкой на статью Jitsi про Last-N, соответствующие IETF RFC и опубликованное поведение Janus, mediasoup и LiveKit. К концу вы будете знать, что делать для своего конкретного целевого числа участников – пересылать, выбирать или смешивать аудиопотоки, – и сколько стоит каждый из этих вариантов.

Число, которое решает всё: кто кого слышит

Прежде чем переходить к архитектуре, запомните один арифметический факт – от него зависит каждое решение по масштабированию в этой статье. В звонке каждый говорящий создаёт один аудиопоток, а каждый слушающий должен его получить. Если все могут одновременно говорить и слышать друг друга, и в комнате находится K человек, то общее количество доставок голоса, которое должна обработать система, составляет: каждый из K человек получает K−1 голосов – то есть K × (K − 1) доставок.

Подставим числа – ведь именно форма роста и есть суть. Формула – на первой строке, умножение – на второй, результат – на третьей.

  • 5 человек: 5 × 4 = 20 доставок голоса.
  • 50 человек: 50 × 49 = 2 450 доставок.
  • 500 человек: 500 × 499 = 249 500 доставок.
  • 5 000 человек: 5 000 × 4 999 = 24 995 000 доставок.

Обратите внимание, что произошло. Переход от 5 к 50 участникам – то есть в десять раз больше людей – привёл не к десятикратному, а примерно к 122-кратному росту числа доставок. Это квадратичный рост: объём работы увеличивается пропорционально квадрату числа участников, поэтому удвоение числа пользователей почти в четыре раза увеличивает нагрузку. Инженеры Jitsi в статье 2015 года о масштабировании конференций выразили ту же мысль прямо: в системе, где каждая точка передаёт медиа всем остальным, «требуемые ресурсы (CPU, пропускная способность сети) растут квадратично с числом точек», и такая архитектура «плохо масштабируется, когда число участников значительно (≈ 50)». Пятьдесят – это порог, после которого наивный подход начинает давать сбои; его появление в заголовке этой статьи не случайно.

Полезный образ. Представьте ужин: шесть гостей – каждый успевает следить за каждым. Шесть человек, тридцать возможных отношений «слушаю – говорю», и это работает. Теперь представьте банкетный зал на пятьсот человек, где все одновременно пытаются говорить со всеми. Это уже не разговор, а рёв. Никакая хитроумная проводка не изменит того, что здесь одновременно возникает четверть миллиона отношений слушания. Решение – не в лучшей проводке. Решение – признать, что большинство этих отношений в любой конкретный момент не нужны, ведь в реальной встрече одновременно говорят лишь несколько человек. Это единственное осознание – передавать только то, что человек реально произносит, – и есть рычаг, который превращает невозможное число обратно в управляемое.

«О различии «активный» и «пассивный». В этой статье активный участник – тот, чей микрофон включён и кто может быть услышан; пассивный – только слушает. На таунхолле на 5 000 человек обычно 3 активных и 4 997 пассивных. Стоимость аудио определяет число активных, а не общее количество участников – и именно разделение этих двух категорий является первым шагом в грамотном проектировании большого звонка.»

Семейство протоколов, с помощью которых браузеры передают живое аудио – WebRTC, – не решает за вас проблему масштабирования. Оно предоставляет канал; решать, какое аудио по нему передаётся на каждом уровне масштабирования, – задача вашей архитектуры. Чтобы понять три подхода, которые мы комбинируем ниже – прямое отправление, пересылку и смешивание, – начните с сопутствующей статьи Аудио в SFU, MCU и P2P, где каждый из них рассмотрен отдельно. Эта статья – о том, что происходит, когда вы масштабируете систему до 50, 500 и 5 000 участников.

Режим первый – до ~50 человек: пересылаем всё

Первый режим – это групповой звонок небольшой или средней численности: ежедневные совещания команды, занятия в классе, заседания совета. Здесь оптимальным решением является Selective Forwarding Unit (SFU) – сервер, который принимает аудиопоток каждого участника и пересылает его дальше, не декодируя звук. Каждый участник отправляет один поток и получает по одному потоку от каждого, кого слушает. Работа сервера проста, поскольку он не декодирует аудио; основная нагрузка – шифрование, о котором мы поговорим позже.

Вот аудиоспецифичный факт, который удивляет даже опытных видеоинженеров: в этом режиме всё аудио пересылается всем и всегда. Знаменитый приём масштабирования Last-N, при котором сервер передаёт только несколько наиболее релевантных видеопотоков, а остальные приостанавливает, был разработан для видео. В оригинальной статье Jitsi прямо указано: «схема Last-N применяется только к видеопотокам, но не к аудио; аудио со всех участников передаётся всегда». Причина в том, что аудио дешёвое и чувствительно к задержкам. Голосовой поток на кодеке Opus занимает около 24–32 тысяч бит в секунду – это доля от объёма видеопотока – и если задержать чьё-то аудио, решая, «релевантен» ли участник, можно упустить первое слово. Поэтому в звонке на 50 человек сервер передаёт каждый голос каждому слушателю, и это нормально: потоки небольшие, и клиент легко справляется с декодированием двух десятков потоков.

Куда же тогда уходит стоимость? В двух местах. Первое – нагрузка шифрования на сервере. WebRTC требует шифровать каждый медиапакет на участке до сервера, поэтому SFU должен расшифровать каждый входящий пакет и заново зашифровать его для каждой исходящей копии. Замеры Jitsi показали рост нагрузки на CPU примерно пропорционально общему битрейту – «в основном за счёт расшифровки и повторного шифрования RTP-пакетов», а не самого аудио, которое никогда не декодируется. Второе – нагрузка декодирования и микширования на клиенте. Ваше устройство декодирует каждый входящий голос и сводит их для динамиков, и эта работа растёт с числом активных говорящих.

Приём, который масштабирует аудио, не нарушая его целостности

Если бы в комнате на 50 человек все 50 сидели с включёнными микрофонами и открытыми микрофонами, результатом стала бы неслушаемая каша фонового шума – пятьдесят потоков звуков от вентиляторов, клавиатур и улицы, сложенных вместе. Два механизма не дают этому случиться, и оба – чистая аудиоинженерия.

Первый – прерывистая передача (DTX): когда микрофон молчит, он фактически перестаёт передавать данные. Opus DTX снижает скорость передачи для молчаливого участника с ~24–32 кбит/с до примерно 1 кбит/с, отправляя лишь крошечные пакеты «комфортного шума» раз в несколько сотен миллисекунд. Поэтому в звонке на 50 человек, где говорят только трое, полноскоростное аудио передают лишь эти трое; остальные 47 участников почти не создают нагрузки. Реальную аудионагрузку в комнате определяют активные говорящие, а не общее количество участников. (Как работают DTX и комфортный шум, см. Детектор речевой активности (VAD) и прерывистая передача (DTX).)

Второй – осведомлённость об активном говорящем. Каждый отправитель указывает громкость каждого аудиопакета в специальном поле заголовка RTP, определённом в IETF RFC 6464 – это число от 0 до 127, соответствующее уровню в децибелах ниже полной шкалы, – и сервер считывает его, не декодируя звук. Хотя сервер пересылает всё аудио, он использует эти значения, чтобы сообщить каждому клиенту, кто является основным говорящим: так интерфейс может выделить его, а клиент – отображать только самых громких. Это фундамент, на котором строится следующий режим.

Рис. 1. Почему масштаб ломает аудио. Пересылка каждого голоса всем (оранжевая) растёт как квадрат размера комнаты. Пересылка лишь нескольких активных говорящих (зелёная) растёт с числом говорящих, которое почти не меняется при росте аудитории. Разрыв между кривыми – это и есть вся инженерная задача.

Режим второй – от 50 до ~500 человек: пересылаем только активных участников

После примерно пятидесяти человек меняются две вещи. Комната почти всегда становится асимметричной – несколько докладчиков и большая, в основном замьюченная аудитория, – и даже пересылка аудио только активных говорящих каждому слушателю начинает накапливаться, потому что число слушателей теперь велико. Голос одного докладчика, идущий к 499 слушателям, – это 499 исходящих копий, которые сервер должен зашифровать. С тремя докладчиками это почти 1 500 операций «зашифровать-и-отправить» на каждый аудиокадр, каждые 20 миллисекунд. Аудио всё ещё дёшево маршрутизировать, но стоимостью становится веерная раздача (fan-out).

Архитектура этого режима по-прежнему основана на SFU, но теперь он пересылает только аудио активных говорящих, а не всех участников. Сервер ранжирует участников по уровню громкости согласно RFC 6464, выявляет тех, кто действительно ведёт речь, и передаёт только их потоки. На общем собрании из 200 человек, где выступает один вице-президент, фактически пересылается лишь один аудиопоток – 199 слушателям; когда кто-то задаёт вопрос, его поток добавляется к передаваемым, а поток вице-президента может временно исключаться. Решение о том, кто является активным говорящим, – ключевая часть этого режима, и принять его корректно сложнее, чем просто определить «кто громче прямо сейчас».

Как выбрать активного говорящего и не ошибиться

Кашель, упавший телефон, громкое «ага» в знак согласия – ничто из этого не должно отбирать слово у докладчика. Отраслевой стандарт – алгоритм идентификации доминирующего говорящего, разработанный Иланой Волфин и Израилем Коэном, – был адаптирован статьёй Jitsi для работы исключительно на уровнях громкости по RFC 6464 без декодирования аудио. Вместо реакции на один громкий пакет он оценивает речевую активность каждого участника сразу в трёх временных окнах: мгновенном – нескольких фонем, среднем – слова-двоих и длинном – короткого предложения, – и объявляет смену говорящего только тогда, когда все три параметра одновременно растут на одном канале. Авторы чётко определили цели поведения: переходный шум и однословные реплики не должны вызывать смену, её может инициировать только начало настоящего речевого всплеска, а допустимая задержка между переходами – «до одной секунды». Относительная громкость голоса не должна влиять на вероятность выбора – тихого докладчика определяют так же надёжно, как и громкого.

Этот алгоритм работает внутри ActiveSpeakerObserver в mediasoup, в логике определения доминирующего говорящего в Jitsi Videobridge и в аналогичных решениях в каждом серьёзном SFU. В результате получается стабильный сигнал «активного говорящего», который выполняет две задачи: указывает SFU, какое аудио пересылать, и сообщает каждому клиенту, какую плитку подсветить.

Арифметика выигрыша

Выигрыш заключается в разнице между квадратичным и линейным ростом. Измерения Jitsi показали: в конференции из 30 участников пересылка фиксированного числа потоков вместо всех сокращает исходящий битрейт на 72–89% – в зависимости от количества пересылаемых потоков. Это превращает квадратичный рост в линейный относительно числа участников. Та же логика работает и для аудио, если пересылать только активных говорящих: нагрузка растёт пропорционально числу говорящих (в реальных встречах оно обычно составляет 1–5) и числу слушателей, а не квадрату общего количества участников. Конкретно: на вебинаре с 500 участниками и 3 активными докладчиками вы отправляете около 3 × 500 = 1 500 аудиопотоков вместо 500 × 499 = 249 500, которые потребовались бы при «полной пересылке» – сокращение в 166 раз, достигнутое исключительно за счёт того, что тишина не передаётся.

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

Рис. 2. Режим два: пересылаем только говорящих. Несколько активных говорящих определяются по уровням громкости по RFC 6464 и веером раздаются всем слушателям; замьюченное большинство почти ничего не стоит благодаря DTX. Сервер никогда не декодирует аудио – он лишь считывает метку громкости и пересылает.

Режим третий – от 500 до 5 000+ человек: смешиваем немногих, раздаём один

На нескольких тысячах участников стеной становится сама веерная раздача. Отправить аудио трёх говорящих 5 000 слушателям – это 15 000 зашифрованных исходящих потоков на каждый аудиокадр, а один клиент, который ещё и отрисовывает видео, не может комфортно принимать и декодировать несколько отдельных аудиопотоков на фоне всего остального. Выход – перестать отправлять отдельные потоки и смешать активных говорящих в один общий поток на сервере, а затем разослать этот единственный поток всем. Это подход Multipoint Control Unit – MCU, – применённый хирургически только к аудио и только к активным говорящим.

Механика важна. Сервер декодирует аудио только у немногих активных говорящих (не всех 5 000 – остальные молчат и исключаются логикой активного говорящего), смешивает их в один поток, кодирует его один раз и отправляет этот единственный поток каждому слушателю. Теперь слушатель скачивает ровно один аудиопоток – независимо от того, 500 или 50 000 человек в комнате. Плагин AudioBridge в Janus – производственный пример именно такого подхода: это «аудио- MCU», и «все аудиопотоки смешиваются, а не ретранслируются», поэтому «создаётся единственное PeerConnection независимо от числа участников», а каждый получает «микс остальных». Стоимость смещается с веерной раздачи в сети на CPU сервера, отвечающий за микширование – но поскольку декодируются только активные участники, а микс создаётся один раз, нагрузка на CPU зависит от числа говорящих, а не от числа слушателей.

Правило N-минус-1 и почему вы никогда не складываете все 5 000

Две детали аудиоинженерии позволяют серверному микшированию работать эффективно. Первая: микс, отправляемый каждому говорящему, должен исключать его собственный голос – иначе он услышит себя с задержкой в долю секунды. Для N участников каждый получает сумму остальных контрибьюторов – микс N-минус-1. Для чистых слушателей это тривиально (они ничего не вносят, поэтому получают полный микс), а для небольшой группы активных говорящих сервер формирует слегка разный микс для каждого. Вторая – и именно это правило делает масштаб возможным – сервер смешивает только несколько самых громких каналов, а не все. Сложение 5 000 аудиосигналов породило бы 5 000 шумовых порогов, превратившихся бы в фоновое шипение громче любого голоса, и потребовало бы 5 000 операций декодирования. Масштабируемый микшер конференции выбирает несколько наиболее активных каналов по уровню звука и смешивает только их – обычно от трёх до шести голосов. Те же параметры громкости из RFC 6464, которые ранее управляли пересылкой в режиме два, теперь отвечают за отбор каналов для микширования в режиме три.

Когда одного сервера недостаточно: каскадирование

У одного сервера есть ограничение по числу участников – вне зависимости от архитектуры. Чтобы выйти за этот предел, в десятки тысяч, производственные системы каскадируют: запускают множество медиасерверов, которые ретранслируют данные друг другу. Благодаря этому участник, подключённый к серверу во Франкфурте, слышит говорящего, подключённого к серверу в Сан-Паулу, не требуя, чтобы какой-либо из серверов обслуживал всех участников напрямую. Опубликованная архитектура LiveKit – яркий пример: пограничные серверы образуют распределённую сетку, координируются через общий слой состояния (Redis) и ретранслируют медиапотоки между регионами – так платформа заявляет поддержку сессий до 100 000 участников с задержкой между ними менее 100 миллисекунд. Каскадирование не меняет логику обработки аудио внутри комнаты – вы по-прежнему пересылаете активных говорящих или смешиваете самых громких – оно лишь распределяет широковещательную рассылку по нескольким машинам, чтобы ни одна из них не достигла своего предела.

Честный финал: на таком масштабе это уже не «звонок»

Есть порог, за которым правильный ответ – признать, что разговор уже не ведётся. Запуск продукта для 50 000 зрителей с тремя докладчиками – это трансляция, а не групповой звонок. Стандартный подход – гибрид: несколько докладчиков и приглашённые на сцену участники аудитории работают в реальном времени через SFU/MCU, обеспечивая настоящее двустороннее взаимодействие, а пассивная аудитория получает смешанный контент по стримингу – например, через Low-Latency HLS по CDN, как настоящий живой видеопоток. Интерактивное ядро остаётся небольшим и реальным; массовый пассивный слой обслуживается инфраструктурой, рассчитанной именно на такие нагрузки. Определить, где провести эту границу – сколько людей действительно должны иметь возможность отвечать, – самое важное решение при масштабировании. Это продуктовое, а не инженерное решение. Стриминговая часть – отдельная дисциплина; см. Аудио в HLS, DASH, CMAF и Аудио в стриминге с низкой задержкой.

Рис. 3. Выбор по масштабу. До ~50: пересылаем всё. До ~500: пересылаем только активных говорящих. Дальше: смешиваем самых громких немногих и либо каскадируем по серверам, либо, если почти никому не нужно отвечать, раздаём программу веером по стримингу с низкой задержкой.

Три режима рядом

Три режима по-разному распределяют одни и те же ресурсы – CPU сервера, пропускную способность веерной раздачи, нагрузку на декодирование у клиента и задержку – по мере роста числа участников. Таблица представляет собой одно из возможных решений. Интерпретируйте количество участников как приблизительные пороги, а не жёсткие границы: реальные значения зависят от настроек кодека, характеристик оборудования и того, сколько человек говорят одновременно.

Свойство~50 человек~500 человек5 000+ человек
АрхитектураSFU, пересылка всегоSFU, пересылка активныхMCU-микс громких; каскад/гибрид
Сервер декодирует аудио?НикогдаНикогдаТолько активных немногих
Что получает каждый слушательКаждый голосГолоса активных говорящихОдин смешанный поток
Главная стоимостьДекод на клиенте + шифрование на сервереВеерная раздача (шифрование на копию)CPU микса (ограничен говорящими)
Потоков скачивает слушательПо одному на активного говорящегоПо одному на активного говорящегоРовно один (микс)
Добавленная задержкаНаименьшая (только пересылка)Низкая (только пересылка)Выше (декод + микс + перекодирование)
Контроль по говорящему (mute, уровни)ПолныйПолныйТеряется при микшировании
Запись одним файломНужен отдельный миксНужен отдельный миксМикс уже существует
Пример из реальностиКомната Jitsi, mediasoup, LiveKitSFU-вебинар в режиме активного говорящегоJanus AudioBridge; каскад LiveKit; гибрид SFU+LL-HLS

Узор становится понятным, когда вы его видите. По мере роста нагрузки стоимость перемещается от клиента (декодирование множества потоков) к серверной сети (распространение копий), а затем – к CPU сервера (микширование). Каждая такая миграция даёт ещё один порядок масштабируемости, но всегда что-то стоит – обычно контроль над говорящим и небольшая задержка. Искусство заключается в том, чтобы переключаться между режимами вовремя: не слишком рано (чтобы не терять простоту передачи) и не слишком поздно (чтобы избежать инцидента).

Частая ошибка: проектировать под среднее, платить за пик

Вот ловушка, в которую чаще всего попадают команды, и она особенно характерна для аудио на большом масштабе. Аудионагрузку встречи определяет не общее число участников и даже не среднее количество говорящих – её задаёт наибольшее число одновременно говорящих, и это число резко возрастает именно в самый неподходящий момент. Общее собрание из 500 человек 55 минут проходит при одном-двух активных участниках, а потом CEO спрашивает: «Есть вопросы?» – и сразу сорок человек начинают говорить одновременно. Если ваша логика обработки активных говорящих пересылает или смешивает всех, кто на мгновение стал громким, этот один момент может потребовать в двадцать раз больше аудиоресурсов, чем в стабильном режиме, – и именно тогда звонок начинает резко деградировать перед самой важной аудиторией.

Лекарство – жёсткий лимит на количество одновременно пересылаемых или смешиваемых участников – обычно от трёх до шести – обеспечивается ранжированием доминирующего говорящего, а также элементом интерфейса, делающим этот лимит очевидным (например, очередь «поднять руку» или сцена, управляемая модератором). Правило Волфин–Коэна, согласно которому «при одновременной речи на нескольких каналах доминирующим считается тот, кто начал говорить первым», как раз и не позволяет ситуации, когда сорок человек пытаются говорить одновременно, превратиться в сорок параллельных потоков: система выбирает лишь тех немногих, кто начал первым, и блокирует остальных. Устанавливайте этот лимит осознанно – не оставляйте его на усмотрение настроек SFU по умолчанию.

Вторая, более тонкая ловушка: разрывы DTX сбивают с толку наивную логику определения активного говорящего. Поскольку при тихом микрофоне в режиме Opus DTX передача пакетов прекращается, компонент, ожидающий пакет каждые 20 миллисекунд, может воспринять тишину как «этот участник отключился» и заставить индикатор активного говорящего мигать. Если индикатор дергается, когда люди делают паузы между предложениями, первым делом проверяйте тайминг DTX, а не алгоритм. Это задокументированное поведение в реальных SFU, и решение – в том, как компонент обрабатывает пропущенные пакеты, а не в значениях громкости.

Где здесь Фора Софт

Мы интегрируем аудио в реальном времени в видеоконференции, e-learning, телемедицину и платформы для живых событий с 2005 года. И вопрос «сколько участников?» мы задаём ещё до написания первой строки медиакода – он определяет архитектуру сильнее любого другого требования. Виртуальный класс на 30 студентов – это простой SFU, пересылающий поток преподавателя и тех, кто включит микрофон; общее собрание компании на 400 человек – это SFU в режиме активного говорящего с ограничением числа одновременно говорящих и модерируемой очередью вопросов; запуск продукта на 10 000 участников – это небольшая интерактивная сцена, подающая смешанный поток с низкой задержкой для пассивной аудитории. Мы проектируем систему под пиковый момент одновременных выступлений, а не под комфортное среднее, потому что видели, что происходит с системой, рассчитанной на стабильную нагрузку, когда кто-то спрашивает: «Есть вопросы?» Когда продукту нужны и настоящая интерактивность на большом масштабе, и качественные записи, мы заранее планируем вычислительные ресурсы микширования и путь записи, а не выявляем их уже под нагрузкой.

Ключевые выводы

  • Стоимость аудио растёт пропорционально квадрату размера комнаты, если каждый голос передаётся всем.
  • До ~50 человек: SFU пересылает всё аудио; DTX делает молчание почти бесплатным.
  • 50–500 человек: передавайте аудио только активных участников на основе уровней громкости по RFC 6464.
  • 5 000+ человек: смешивайте аудио самых громких участников в один поток, используйте каскадирование или переходите на гибридную архитектуру.
  • Никогда не объединяйте все каналы – смешивайте только три–шесть самых активных говорящих.
  • Проектируйте систему под пиковое количество одновременно говорящих, а не под среднее.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.