Real-Time Backend
Signaling сервер
WebRTC P2P напрямую устанавливает соединение между двумя браузерами через NAT - но кто-то должен их сначала познакомить. Signaling сервер делает это за 10-20 сообщений, после чего полностью выходит из игры.
- **Livekit** (open-source WebRTC platform) использует Redis pub/sub для signaling между инстансами: каждый WebSocket server подписывается на каналы своих rooms и форвардит сообщения через Redis. Горизонтально масштабируется до тысяч инстансов
- **Daily.co** генерирует временные TURN credentials со сроком 24ч через свой signaling API. Каждый join-запрос возвращает свежие credentials - злоупотребление credentials конкретного пользователя ограничено TTL
- **Twilio Video** публикует статистику: их signaling сервера обрабатывают пик в 50 млн сообщений в день (SDP + ICE candidates) при минимальной вычислительной нагрузке - это чистый relay
- **Cloudflare Calls** предоставляет managed signaling + TURN. Разработчику не нужно поднимать свой сервер - только клиентский SDK и один API endpoint
Signaling Role
Signaling server - это 'свидетель' при установке WebRTC соединения. Он не обрабатывает медиа, не декодирует видео, не хранит данные. Его единственная задача - передать SDP и ICE candidates между двумя peers до того, как они смогут общаться напрямую.
WebRTC намеренно не стандартизирует signaling протокол - это решение оставлено разработчику. Можно использовать WebSocket, Server-Sent Events, даже QR-код или email. На практике 99% реализаций используют WebSocket из-за двунаправленности и низкой latency.
**Масштаб:** Signaling server для 10000 одновременных WebRTC сессий обрабатывает примерно 10-50 сообщений на сессию (SDP + ICE candidates). Это ~100-500K сообщений за сессионный пик. После установки соединений нагрузка падает почти до нуля - только heartbeat. Signaling горизонтально масштабируется, в отличие от TURN сервера.
После успешного Offer/Answer обмена и ICE negotiation - какую роль продолжает играть signaling server?
Signaling Protocol
Несмотря на то что WebRTC не стандартизирует signaling, на практике сложился де-факто стандарт: JSON-сообщения с полем `type` через WebSocket. Минимальный набор типов: `offer`, `answer`, `ice-candidate`, `hangup`.
**Масштабирование signaling:** простой relay работает пока все peers подключены к одному server-инстансу. При горизонтальном масштабировании нужен pub/sub (Redis, NATS) для cross-instance relay. Livekit (open-source WebRTC platform) использует Redis pub/sub для signaling между инстансами.
Signaling сервер масштабируется горизонтально на 3 инстанса. Alice на инстансе 1, Bob на инстансе 2. Как relay сообщения от Alice до Bob?
Perfect Negotiation
В WebRTC race condition - это не edge case, это штатная ситуация. Alice создаёт offer, Bob тоже создаёт offer одновременно. Оба получают offer от другого пока у самих уже есть local offer. Это называется **glare** - столкновение offer'ов. Без обработки glare соединение зависает.
**Perfect Negotiation** - паттерн из WebRTC спецификации W3C для корректной обработки glare без сложной координации. Идея: один peer назначается 'polite' (уступает), другой - 'impolite' (настаивает). При glare polite-peer откатывает свой offer и принимает offer от impolite-peer.
**Implicit rollback:** `await pc.setRemoteDescription(sdp)` когда signalingState='have-local-offer' раньше требовал явного `setLocalDescription({type:'rollback'})`. В современных браузерах (Chrome 80+, Firefox 75+) setRemoteDescription делает implicit rollback автоматически - именно это делает Perfect Negotiation лаконичным.
В Perfect Negotiation паттерне что делает 'polite' peer при получении offer во время glare (когда сам создаёт offer)?
Signaling Impl
Production signaling сервер должен решать несколько задач за пределами базового relay: аутентификация WebSocket соединения, room management, обработка reconnect, rate limiting против DoS. Рассмотрим production-ready структуру.
**TURN credentials rotation:** статические TURN credentials в коде - уязвимость. Production подход: signaling сервер генерирует временные TURN credentials (TTL 24ч) через REST API coturn/Cloudflare TURN. Клиент запрашивает credentials при join, получает `{ username, credential, ttl }` и использует для RTCPeerConnection. Twilio, Daily.co генерируют credentials на своих бекендах именно так.
Signaling сервер - это TURN сервер; они делают одно и то же
Signaling и TURN - разные серверы с разными задачами: signaling обменивает SDP/ICE metadata (текст, низкий трафик), TURN relay-ит медиапоток (видео/аудио, высокий трафик)
Signaling сервер после установки соединения почти не нагружен - только редкие renegotiation events. TURN сервер при активной сессии передаёт мегабиты видео непрерывно. Они масштабируются по-разному: signaling - stateless WebSocket relay, TURN требует широкой сетевой полосы. Смешивать их в одном сервисе - архитектурная ошибка.
Почему TURN server credentials не следует хардкодить в клиентском коде?
Итоги
- Signaling server - relay для SDP/ICE metadata; после P2P handshake его нагрузка падает до нуля; масштабируется через Redis pub/sub
- Perfect Negotiation решает glare (collision offers) через polite/impolite роли; polite peer делает rollback своего offer при получении чужого
- TURN credentials должны быть временными (TTL 24ч) и генерироваться signaling сервером per-session; хардкод credentials открывает relay для злоупотребления
Связанные темы
Signaling сервер - точка интеграции WebRTC с остальным backend:
- WebRTC основы — Предыдущий урок: архитектура P2P, ICE, SDP - база для понимания что именно relay-ит signaling сервер
- WebSocket сервер — Signaling использует WebSocket как транспорт; те же паттерны room management и message routing применимы к обоим
- Аутентификация WebSocket — JWT в query parameter при WS upgrade - стандартный паттерн auth для signaling; те же механизмы что и в WS auth уроке
Вопросы для размышления
- Signaling протокол не стандартизирован в WebRTC спецификации. Какие преимущества и недостатки даёт эта свобода разработчику?
- Perfect Negotiation требует определить кто 'polite' а кто 'impolite'. Как это делать в группе из 3+ участников, где каждый может инициировать renegotiation?
- При reconnect (разрыв соединения) нужно ли начинать Offer/Answer заново или можно продолжить с существующим RTCPeerConnection через ICE restart?