From 8e4503825110a60d297d2667970b70f1a2bd5b98 Mon Sep 17 00:00:00 2001 From: Max Ronzhin Date: Sun, 2 Aug 2026 12:33:53 +0300 Subject: [PATCH] =?UTF-8?q?fix(livekit):=20=D0=BE=D0=B4=D0=B8=D0=BD=20UDP-?= =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE?= =?UTF-8?q?=20=D0=B4=D0=B8=D0=B0=D0=BF=D0=B0=D0=B7=D0=BE=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=20101=20=D0=BF=D0=BE=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Диапазон 54000-54100/udp заставлял Docker поднимать по отдельному docker-proxy на каждый порт — весь медиатрафик шёл лишним userland-хопом. rtc.udp_port переключает LiveKit на мультиплексирование ICE-сессий через один порт; TURN и остальные связи (redis/nginx/webhook/prometheus) не задеты. Проверено локально lk load-test — 0% потерь пакетов, ICE во всех сессиях выбирает новый порт. --- deploy/docker-compose.yml | 15 +++++++++------ deploy/livekit/livekit.yaml.template | 14 +++++++++----- docs/deploy/DEPLOYMENT.md | 6 +++--- docs/deploy/capacity.md | 15 +++++++++------ 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 3002abf..407b837 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -407,16 +407,19 @@ services: # 7880 (signaling) — ТОЛЬКО loopback: nginx проксирует /livekit/ по имени # `livekit:7880` внутри docker-сети (см. nginx.conf.template), браузеры # снаружи ходят через nginx/443 (wss://), прямой доступ к 7880 им не - # нужен. 7881/tcp и UDP-диапазон ниже — реальные медиа-порты, остаются + # нужен. 7881/tcp и UDP-порт ниже — реальные медиа-порты, остаются # публичными. ports: - "127.0.0.1:7880:7880" # HTTP/WebSocket signaling - "7881:7881" # RTC TCP fallback - # Узкий диапазон для dev на macOS: широкий (50000-60000) почти всегда - # конфликтует с занятыми UDP-портами хоста и тормозит Docker Desktop. - # 54000+ выбран после конфликтов: нижние диапазоны (50000+, 52000+) - # занимают Steam/системные процессы macOS и эфемерные QUIC-соединения. - - "54000-54100:54000-54100/udp" # WebRTC media (ICE) + # Один порт вместо диапазона (был 54000-54100/udp) — LiveKit + # мультиплексирует все ICE-сессии через него (rtc.udp_port в + # livekit.yaml.template), а не открывает по порту на участника. + # На диапазон Docker поднимал по docker-proxy на КАЖДЫЙ порт — + # 101 порт держали 101 лишний userland-процесс на медиапути. + # 54000 выбран, как раньше: нижние диапазоны (50000+, 52000+) на + # macOS заняты Steam/системными процессами и эфемерными QUIC. + - "54000:54000/udp" # WebRTC media (ICE, мультиплекс) depends_on: redis: condition: service_healthy diff --git a/deploy/livekit/livekit.yaml.template b/deploy/livekit/livekit.yaml.template index cbbee32..93cdaef 100644 --- a/deploy/livekit/livekit.yaml.template +++ b/deploy/livekit/livekit.yaml.template @@ -15,16 +15,20 @@ port: 7880 rtc: tcp_port: 7881 - # Диапазон сужен для dev (см. комментарий в docker-compose.yml); в проде - # расширить и синхронизировать с пробросом портов. - port_range_start: 54000 - port_range_end: 54100 + # Один UDP-порт с мультиплексированием ICE вместо диапазона портов. + # Раньше здесь был port_range_start/port_range_end (54000-54100) — под + # каждый порт диапазона Docker поднимал отдельный процесс docker-proxy + # (userland-прокси на весь медиатрафик), на 101 порт — 101 процесс. + # udp_port переключает LiveKit на единственный сокет с демультиплексацией + # по ICE ufrag; port_range_start/end при заданном udp_port игнорируются + # (проверено по исходникам сервера) — оставлять их рядом бессмысленно. + udp_port: 54000 # use_external_ip: false + node_ip=127.0.0.1 — режим для локальной # разработки (Docker Desktop): use_external_ip=true определяет публичный # IP через STUN, что в контейнере на macOS даёт недостижимый изнутри хоста # внутренний IP (172.18.x.x) — DTLS-хендшейк по data-каналам не проходит # ("dtls timeout" в логах). node_ip=127.0.0.1 работает, потому что порты - # 7881/tcp и 54000-54100/udp проброшены на loopback хоста, а браузер-клиент + # 7881/tcp и 54000/udp проброшены на loopback хоста, а браузер-клиент # запускается на том же хосте. # В проде (LIVEKIT_USE_EXTERNAL_IP=true, LIVEKIT_NODE_IP=<внешний IP/домен # сервера> в .env) клиенты снаружи хоста подключаются по этому адресу — diff --git a/docs/deploy/DEPLOYMENT.md b/docs/deploy/DEPLOYMENT.md index 24736f2..ea20ca2 100644 --- a/docs/deploy/DEPLOYMENT.md +++ b/docs/deploy/DEPLOYMENT.md @@ -81,7 +81,7 @@ ufw allow 22/tcp # SSH — сузьте до вашей сети, если ufw allow 80/tcp # HTTP (редирект на HTTPS + ACME-challenge) ufw allow 443/tcp # HTTPS ufw allow 7881/tcp # LiveKit RTC TCP fallback (профиль media) -ufw allow 54000:54100/udp # LiveKit WebRTC media (ICE), см. docker-compose.yml +ufw allow 54000/udp # LiveKit WebRTC media (ICE, мультиплекс), см. docker-compose.yml # TURN (coturn) — только если включаете раздел 8. Нужны ОБА пункта: # сигнальные порты И диапазон relay-аллокаций (min-port/max-port из # deploy/coturn/turnserver.conf). Без второго TURN отвечает на запросы, но @@ -276,7 +276,7 @@ docker compose -f deploy/docker-compose.yml --env-file .env --profile monitoring # 1. Все сервисы healthy docker compose -f deploy/docker-compose.yml --env-file .env ps -# 2. Наружу открыто только ожидаемое (80/443/7881 + udp 54000-54100, +# 2. Наружу открыто только ожидаемое (80/443/7881 + udp 54000, # плюс 3478 tcp+udp, если включили TURN — раздел 8) ss -ltnp @@ -318,7 +318,7 @@ Protocols`. Проверьте **гостевой вход** (`/j/` в п **Статус: НЕ обязателен.** Реальное кросс-сетевое тестирование (участники в разных сетях/на разных устройствах) прошло успешно **без** раздачи TURN клиентам — комбинации `LIVEKIT_USE_EXTERNAL_IP=false` + реальный -`LIVEKIT_NODE_IP` + проброшенный UDP-диапазон `54000-54100` (шаг 1, +`LIVEKIT_NODE_IP` + проброшенный UDP-порт `54000` (шаг 1, firewall) хватает для подавляющего большинства сетей. Включайте этот раздел только если у вас есть конкретные пользователи за CGNAT или жёстким корпоративным firewall, которые не могут установить медиа-соединение diff --git a/docs/deploy/capacity.md b/docs/deploy/capacity.md index 43acca3..bb4596a 100644 --- a/docs/deploy/capacity.md +++ b/docs/deploy/capacity.md @@ -179,12 +179,15 @@ dev-стека. профилей битрейта заводить не требуется; при необходимости ограничить верхнюю границу — `videoEncoding`/`simulcastLayers` на фронтенде (клиентский SDK, вне скоупа devops-части). -4. **UDP-диапазон 54000-54100 (101 порт)** не был узким местом ни на одной - ступени (максимум 60 участников в тесте) — при планировании прод-узла с - ожидаемым бОльшим числом одновременных участников across все комнаты - узла держать `port_range_end - port_range_start` заметно больше пикового - числа участников на узле (LiveKit резервирует пару портов на участника - на медиа-транспорт). +4. **UDP-диапазон 54000-54100 (101 порт)**, на котором проводился этот тест, + не был узким местом ни на одной ступени (максимум 60 участников). Тогда + же с ним была цена: под каждый порт диапазона Docker держал отдельный + процесс `docker-proxy` — 101 порт-101 процесс на медиапути, весь трафик + шёл лишним userland-хопом. С переходом на `rtc.udp_port` (один порт, + мультиплексирование по ICE ufrag внутри LiveKit) рекомендация «держать + диапазон шире пикового числа участников» больше не актуальна — портов + для планирования ёмкости не остаётся вовсе, LiveKit разводит участников + поверх одного сокета сам. 5. **STUN/TURN-находка (см. «Методика») —** рекомендуется отдельной задачей зарегистрировать `deploy/coturn/` в `rtc.turn_servers` LiveKit и на проде, а не только для теста — иначе клиенты в вырожденном случае