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
- **Участник уходит и возвращается** - recorder фиксирует gap, compositor вставляет black frame или placeholder на промежутке
- **Смена layout** (speaker view → grid) - compositor переключает FFmpeg filter graph на лету через sendcmd
- **Screen sharing** - отдельный видеотрек с более высоким приоритетом качества (1080p vs 720p для камеры)
- **Сбой 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.
Процесс переключения участника
- **Signal**: хост инициирует разбивку, сервер создаёт N room записей в Redis
- **Assignment**: участникам рассылается BREAKOUT_ASSIGNED событие через WebSocket с roomId назначения
- **Disconnect from main**: клиент закрывает peer connection с main SFU-контекстом
- **Reconnect**: клиент создаёт новый WebRTC peer connection к breakout SFU-контексту (новый SDP offer/answer)
- **State preservation**: chat history main room сохраняется, breakout room начинает с чистым чатом
- **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 при переключении. Как можно ускорить этот процесс, чтобы переключение было менее заметным для пользователя?