Real-Time Backend

Design: Video Conferencing

В апреле 2020 Zoom обслуживал 300 миллионов участников встреч в день - больше, чем всё население США. За три месяца платформа выросла в 20 раз. Как система не сложилась под такой нагрузкой - и что нужно спроектировать, чтобы повторить это?

  • Zoom (2020): 300 млн daily meeting participants, SFU-архитектура с глобальными edge-кластерами и consistent hashing по roomId
  • Google Meet: миграция с DTLS/SRTP на QUIC transport снизила задержку на 15-20% при плохом соединении у пользователей
  • AWS Chime SDK: managed SFU + Amazon Transcribe real-time транскрипция + recording pipeline через S3 и Lambda - всё как API

Архитектура видеоконференций: SFU vs MCU

Zoom в апреле 2020 обработал 300 млн участников встреч за один день. Это не просто «видеозвонки» - это задача маршрутизации сотен тысяч медиапотоков в реальном времени с задержкой менее 150 мс. Архитектурный выбор определяет, справится ли система или сложится.

MCU vs SFU

  • MCU (Multipoint Control Unit) — Сервер декодирует все входящие потоки, смешивает их в один composed-поток и отправляет каждому участнику единый видеоряд. Нагрузка на сервер: O(N) декодирований + 1 микширование. Клиент получает один поток - экономия полосы. Проблема: CPU-взрыв при 100+ участниках.
  • SFU (Selective Forwarding Unit) — Сервер только маршрутизирует пакеты - не декодирует, не смешивает. Каждый клиент получает N-1 потоков и сам рендерит layout. Нагрузка на клиент растёт с N, но серверная нагрузка линейная и дешёвая. Zoom, Google Meet, AWS Chime - все перешли на SFU.

Реальные системы используют гибрид: SFU для распределения + серверный simulcast. Каждый участник публикует три версии видео (1080p/360p/180p). SFU выбирает нужный слой для каждого подписчика в зависимости от его bandwidth - это называется **Adaptive Bitrate (ABR) forwarding**.

WebRTC стек

Google Meet в 2020 мигрировал с DTLS/SRTP over UDP на QUIC transport. QUIC даёт встроенное мультиплексирование потоков без head-of-line blocking - потеря пакета аудио не блокирует доставку видео. Результат: задержка снизилась на 15-20% при плохом соединении.

Геодистрибуция

Zoom строит региональные кластеры (US, EU, APAC) с dedicated backbone между ними. Клиент подключается к ближайшему edge-серверу через WebRTC, дальше медиа идёт по внутренней сети оператора - это даёт предсказуемую латентность вместо капризного публичного интернета.

В чём главное преимущество SFU перед MCU при 50 участниках в звонке?

Room Management: состояние встречи

Комната видеоконференции - это распределённый объект с состоянием: список участников, media tracks каждого, права (mute/unmute, host controls), chat history. При 100 000 активных комнат одновременно возникает задача синхронизации состояния между несколькими edge-серверами.

Структура данных комнаты

Хранение и синхронизация

Room state хранится в Redis с TTL. При join участника: атомарный HSET + SADD в Redis, затем pub/sub событие всем edge-серверам комнаты. Каждый SFU держит локальную копию room state в памяти - это кеш для быстрого принятия решений о forwarding.

  • **Redis Cluster** - primary store для room state, TTL = время звонка + 1 час
  • **Pub/Sub** - события (join/leave/mute/unmute) рассылаются всем SFU комнаты через Redis Pub/Sub или Kafka
  • **Waiting Room** - отдельная очередь в Redis, хост видит список и апрувит поочерёдно
  • **Active Speaker Detection** - SFU отслеживает RMS уровень аудио-пакетов, переключает «основного говорящего» каждые 500 мс

Signaling: WebSocket координация

При reconnect (потеря соединения) участник получает новый WebRTC peer, но room state в Redis сохраняется. Signaling сервер детектирует reconnect по userId и восстанавливает контекст - участник не теряет место в очереди waiting room и не слетает с роли co-host.

Масштабирование при пиковой нагрузке

Zoom в марте 2020 столкнулся с 20x ростом нагрузки за две недели. Signaling stateless горизонтально масштабируется легко - любой инстанс может обслужить любой запрос через Redis. Проблема - SFU: каждый медиа-сервер держит WebRTC peer connections в памяти, миграция peer между серверами без reconnect невозможна.

Решение Zoom: consistent hashing по roomId на SFU-кластере. Все участники комнаты всегда попадают на один набор SFU-серверов. При отказе сервера - клиенты переподключаются (reconnect < 5 секунд), room state восстанавливается из Redis.

Почему signaling-серверы масштабировать проще, чем SFU media-серверы?

Recording Pipeline: запись встреч

Запись видеоконференции на первый взгляд - «просто сохранить поток». На практике: нужно смешать N видеотреков + аудио, обработать переподключения участников, применить layout (grid/speaker view), транскодировать в MP4 и доставить пользователю. AWS Chime SDK и Zoom предоставляют recording pipeline как отдельный сервис.

Два режима записи

  • Cloud Recording — Специальный recorder-инстанс подключается к SFU как обычный участник, получает все треки через WebRTC, смешивает на сервере (compositor), пишет в S3. Транскодирование в фоне через FFmpeg-воркеры. Итог: MP4 в облаке, доступен по ссылке.
  • Local Recording — Клиент записывает MediaStream через MediaRecorder API прямо в браузере. Формат: WebM (VP8+Opus). Нет серверных расходов, но: нет server-side layout, запись останавливается при потере соединения, файл на диске клиента.

Cloud Recording Pipeline

Обработка edge cases

  1. **Участник уходит и возвращается** - recorder фиксирует gap, compositor вставляет black frame или placeholder на промежутке
  2. **Смена layout** (speaker view → grid) - compositor переключает FFmpeg filter graph на лету через sendcmd
  3. **Screen sharing** - отдельный видеотрек с более высоким приоритетом качества (1080p vs 720p для камеры)
  4. **Сбой recorder-инстанса** - резервный recorder подключается с offset'ом, финальный compositor мёржит оба сегмента

Zoom хранит recordings в S3 с lifecycle policy: 30 дней hot storage (S3 Standard), затем Glacier для архива. Транскодирование запускается через SQS очередь - при пике (конец рабочего дня) воркеры автоматически скейлятся через AWS Auto Scaling по длине очереди.

Транскрипция и AI-обработка

После MP4: аудиотрек извлекается и отправляется в Whisper / AWS Transcribe. Результат - WebVTT субтитры + временные метки спикеров (speaker diarization). Это позволяет строить AI-саммари встречи. AWS Chime SDK предоставляет Amazon Transcribe как managed-сервис с real-time транскрипцией прямо во время звонка.

Recorder-инстанс в cloud recording подключается к SFU как:

Breakout Rooms: виртуальные подгруппы

Breakout rooms - функция разбивки участников на подгруппы с изолированным аудио/видео. Zoom запустил её в 2020, и она стала killer feature для онлайн-образования. За простым UX скрывается нетривиальная задача: переключить 100 участников между комнатами за секунды без потери состояния.

Архитектура breakout rooms

Каждый breakout room - это полноценная изолированная комната со своим SFU-контекстом. При создании N breakout rooms система резервирует N дополнительных media-routing слотов на существующем SFU-кластере. Изоляция обеспечивается на уровне WebRTC: каждый участник имеет отдельный peer connection для breakout room.

Процесс переключения участника

  1. **Signal**: хост инициирует разбивку, сервер создаёт N room записей в Redis
  2. **Assignment**: участникам рассылается BREAKOUT_ASSIGNED событие через WebSocket с roomId назначения
  3. **Disconnect from main**: клиент закрывает peer connection с main SFU-контекстом
  4. **Reconnect**: клиент создаёт новый WebRTC peer connection к breakout SFU-контексту (новый SDP offer/answer)
  5. **State preservation**: chat history main room сохраняется, breakout room начинает с чистым чатом
  6. **Return**: по сигналу «end breakouts» - обратный процесс, все возвращаются в main через reconnect

Broadcast от хоста

Хост может отправить сообщение всем breakout rooms одновременно. Реализация: signaling server получает BROADCAST_TO_BREAKOUTS событие, публикует его в Redis Pub/Sub channels всех дочерних комнат. Каждый SFU-контекст доставляет сообщение своим участникам через WebSocket. Задержка delivery: менее 100 мс.

Таймер и автовозврат

Zoom поддерживает таймер breakout sessions: хост устанавливает лимит (например, 10 минут). За 60 секунд до окончания - countdown notification всем участникам. По истечении: автоматический RETURN_TO_MAIN сигнал. Реализация: отложенная задача в Redis (EXPIRE key) или scheduled job в очереди задач.

Производительность при массовом создании breakout rooms: создание 50 breakout rooms для 500 участников занимает около 2-3 секунд. Узкое место - не SFU (контексты создаются мгновенно), а fan-out WebSocket уведомлений через signaling layer. Решение: параллельная рассылка с batching.

Breakout rooms - это отдельные физические серверы, выделяемые под каждую подгруппу

Breakout rooms - это изолированные логические контексты (routing namespaces) на том же SFU-кластере, что и main room

Выделять отдельный физический сервер под каждую breakout room из 3-4 человек экономически бессмысленно и создаёт проблему cold start (10-30 секунд на запуск). SFU-контексты создаются в памяти мгновенно. Изоляция достигается на уровне routing таблиц, а не физическим разделением.

При переходе участника из main room в breakout room что происходит с WebRTC peer connection?

Итоги

  • **SFU vs MCU**: SFU форвардит RTP без декодирования - линейная серверная нагрузка. MCU микширует - экономия bandwidth клиента ценой CPU-взрыва при масштабе. Все крупные платформы выбрали SFU.
  • **Room state в Redis**: signaling stateless, room state в Redis Pub/Sub - это позволяет горизонтально масштабировать signaling. SFU stateful по peer connections - масштабируется consistent hashing.
  • **Recording = WebRTC participant**: cloud recorder подключается как headless WebRTC клиент к SFU, получает треки, compositor смешивает через FFmpeg, результат в S3 → transcoder очередь → MP4.
  • **Breakout rooms = логические namespace**: создаются в памяти SFU-кластера мгновенно, переключение участника = новый WebRTC handshake (1-3 сек). Broadcast от хоста через Redis Pub/Sub fan-out.

Связанные темы

Видеоконференции объединяют несколько фундаментальных тем распределённых систем:

  • WebRTC и P2P протоколы — Транспортный стек: DTLS/SRTP шифрование, ICE/STUN для NAT traversal, QUIC как альтернатива
  • Redis Pub/Sub и очереди — Room state синхронизация между SFU-кластерами, fan-out событий участникам, recording job queue
  • Consistent Hashing — Маршрутизация участников одной комнаты на один набор SFU-серверов для минимизации inter-server traffic
  • CDN и S3 доставка — Хранение и доставка recording файлов: S3 hot storage → Glacier archive → CloudFront CDN для воспроизведения

Вопросы для размышления

  • Если бы потребовалось поддержать 1000 участников в одной комнате (вебинар), как изменилась бы SFU-архитектура? Что стало бы узким местом первым?
  • Recording pipeline хранит raw chunks в S3 перед транскодированием. Какой trade-off это создаёт между стоимостью хранения и надёжностью при сбое compositor-сервера?
  • Breakout rooms требуют нового WebRTC handshake при переключении. Как можно ускорить этот процесс, чтобы переключение было менее заметным для пользователя?

Связанные уроки

  • sd-01-intro
Design: Video Conferencing

0

1

Войти