3 мин чтения#infrastructure#engineering#sports

Лимит на 200 зрителей поверх MistServer

На VM в Selectel один гигабитный порт. При потоке 3 Мбит/с примерно 300 зрителей забивают его целиком — вместе с запасом для приёма сигнала, SSH и обычной работы сервера.

Перед живым международным турниром я поставил предел в 200 зрителей, около 600 Мбит/с. Моё правило здесь простое: лучше аккуратно отказать 201-му, чем дать перегруженному порту испортить видео всем трёмстам.

В MistServer такого лимита нет

В MistServer OSS 3.x нет штатного глобального ограничения по числу зрителей или суммарной исходящей полосе. Проверил по документации: встречающиеся в сети утверждения об обратном ничем не подтверждены.

Два похожих механизма задачу не решают:

LIVE_BANDWIDTH работает как грубый аварийный выключатель. Ответ false убивает весь буфер потока, а не одну новую сессию. Для боевого контура это непригодно → maxkbps у RTMP-коннектора ограничивает входящий поток. Зрительскую отдачу он не видит

Значит, решение должно стоять в момент допуска новой сессии.

USER_NEW как точка входа

Триггер USER_NEW отправляет запрос небольшому синхронному обработчику на Python. Он работает как служба systemd и слушает только loopback на :9901.

На каждое подключение обработчик:

→ читает текущее число зрителей из active_streams → пропускает ingest-коннекторы мимо лимита — входящий сигнал нельзя случайно отрезать зрительским правилом → разрешает новую сессию, пока счётчик ниже 200 → пишет решение в JSON-журнал: поток, тип коннектора, адрес, счётчик и причина отказа

Так журнал допуска заодно стал аналитикой отказов. Можно увидеть, сколько людей пришло после заполнения порта, не добавляя отдельную систему измерения.

Обработчик сделан fail-open: если служба на :9901 недоступна или не может получить счётчик, MistServer пропускает зрителя. Ошибка моей обвязки не должна погасить работающий эфир. Жёсткую границу полосы позже даст гипервизор.

Первый вариант я зарегистрировал неправильно: новый синхронный обработчик заменил уже работающий асинхронный обработчик телеметрии. Поймал это на проверке конфигурации и добавил ограничитель вторым обработчиком, рядом с прежним. Один триггер умеет обслуживать оба — но только если явно сохранить оба назначения.

Проверка от синтетики до реального отказа

Матрица прошла целиком:

→ обычный зритель допускается → при искусственном cap=0 зритель получает отказ → ingest проходит даже при cap=0 → триггер срабатывает на свежем потоке с реальным IP → при cap=1 удерживаемая сессия занимает единственное место, а подключение со стороннего облачного IP отклоняется

Последний тест был важнее остальных. Отклонённый зритель не висит на пустом запросе: MistServer возвращает чистый плейлист с #EXT-X-ERROR: Shutting down due to session end. Клиент получает конечный ответ, порт остаётся в рабочем диапазоне.

Старые процессы не подхватывают новый триггер

Есть один эксплуатационный нюанс: процессы потоков, запущенные до регистрации обработчика, продолжают жить со старой конфигурацией. Ограничение начинает действовать для них только после перезапуска потока.

Поэтому порядок выкатки здесь такой: зарегистрировать оба обработчика, проверить их список, перезапустить поток, затем повторить внешний тест. Простое сохранение настройки недостаточно.

Следующий шаг уже помещается в тот же обработчик: MistServer выдаёт каждой сессии ?tkn=, туда ляжет проверка HMAC-подписи ссылки. Жёстким ограничителем станет net0 rate 700 Mbit в Proxmox — после турнира, без переподключения сетевого интерфейса в ночь перед эфиром.

Дальше — по мере поступления.

Читать по теме