Вещание онлайн-видео с помощью nginx

в 8:56, , рубрики: Flash-платформа, nginx, nginx-rtmp-module, rtmp, системное администрирование, метки: , ,

Что такое онлайн-видео?

Под термином онлайн-видео я понимаю длительное вещание какого-то живого видеосигнала (к примеру, из телестудии). Традиционные средства отдачи видео (flv- и mp4-стриминг) в данном случае не работают, просто потому что файла, содержащего весь видеопоток, не существует.

В этой статье речь будет идти не об организации видеохостинга, а об организации видеовещания в прямом эфире. Это две принципиально разные задачи, и обычно способы их решения существенно отличаются друг от друга.

RTMP-протокол

RTMP — Real Time Messaging Protocol (вики) — протокол, который обычно используется для раздачи живого видео- и аудиоконтента клиентам. Он удобен тем, что в AS3 есть его поддержка из коробки, требует не слишком много ресурсов на клиенте и поддерживает множество плюшек (например, трансляцию с переменными битрейтами и переключение клиентов на более высокое качество при наличии свободного канала).

NB: Помимо RTMP существует набор других протоколов вещания медиапотоков (RTSP, Apple HTTP Live Streaming и др.), но в этой статье они не рассматриваются.

Протокол RTMP — детище компании Adobe. Единственным официальным сервером, которым можно вещать RTMP-поток, является Adobe Flash Media Server. Его цена и производительность, к сожалению, оставляют желать лучшего, поэтому различными разработчиками были предприняты попытки создать более или менее совместимые альтернативные реализации протокола. К сожалению, у RTMP-протокола есть известные проблемы с лицензированием, к примеру, его официальная спецификация, если следовать ей строго, не позволяет написать работающий RTMP-сервер. Тем не менее, существует несколько реализаций:

  • Red5 — один из первых RTMP-серверов, написан на Java
  • Wowza — проприетарный RTMP-сервер, написан на Java. Помимо RTMP, поддерживает также RTSP, Apple HLS, и Smoothstreaming (Silverlight)
  • erlyvideo — проприетарный RTMP-сервер (есть и бесплатная версия), написан на Erlang. Проект пишется русскими программистами и активно развивается.

Java тормозит

В тестах, которые я проводил, Red5 и Wowza показали неприлично низкую производительность. При мегабитном видеопотоке Wowza при 1000 зрителей онлайн съедала уже около 300% процессорного времени (Intel Xeon E5607). Если требуется вещать хотя бы для 20000 человек онлайн, то нужно закупать 20 серверов? Это слишком дорого.

Что же делать?

Использовать неблокирующие операции. Тормоза в Wowza и Red5 следуют из-за далеко не самой оптимальной схемы обработки событий. Для реализации действительно быстрого стримингового сервера, нужно использовать эффективный метод обработки событий (для linux это epoll). Именно такую схему работы и реализовал Roman Arutyunyan (блог, github-профиль) в своём RTMP-сервере, реализованном как модуль к nginx.

nginx-rtmp-module

Достоинства:

  • Нереально шустрый. На том же физическом сервере, который я использовал для тестов Wowza, nginx выдержал 2500 мегабитных соединений на ядро, т.е. 10000 на весь сервер целиком.
  • Удобные конфиги :). После километровых XML-конфигов Wowza эти выглядят спасением.
  • Отзывчивость автора к фичреквестам.

Недостатки:

  • Проект молодой, наличествуют баги, которые, впрочем, оперативно исправляются.
  • Небольшая функциональность. Сервер вещает только в RTMP, перекодировка появилась буквально несколько дней назад, имеет статус экспериментальной и фактически является обёрткой над ffmpeg. UNIX-way во всей своей красе.
  • Нет многопоточности. Модуль может работать только в том случае, если nginx запускается с одним воркером. Для утилизации всех процессорных ядер нужно запускать несколько воркеров на разных IP-адресах и/или портах.

Многопоточность можно реализовать с помощью примерно такого костыля (Ubuntu):

    for ip in $(cat /etc/network/interfaces | grep address | awk '{print $2}') ; do
        touch /etc/nginx/nginx.$ip.conf
        cp /etc/nginx/nginx.conf.skel /etc/nginx/nginx.$ip.conf
        sed -i "s/%IPADDR%/${ip}/g" /etc/nginx/nginx.$ip.conf
        /usr/sbin/nginx -c /etc/nginx/nginx.$ip.conf
    done

При этом у вас должен быть написан скелет конфига с указанием %IPADDR% вместо IP-адреса. Например, такой:

worker_processes  1;

error_log   logs/error.%IPADDR%.log debug;

pid /var/run/nginx.%IPADDR%.pid;

worker_rlimit_nofile 65536;

events {
    worker_connections  16384;
}

rtmp {
        server {
                listen %IPADDR%:1935;
                chunk_size 4000;
                application live {
                        live on;
                        pull live stream 193.9.17.213;
                }
        }
}

http {
        server {
                listen %IPADDR%:8080;
                location /stat {
                        rtmp_stat all;
                        rtmp_stat_stylesheet stat.xsl;
                }
                location /stat.xsl {
                        root /srv/nginx/html;
                }
        }
}

Впрочем, автор обещает реализовать нормальную многопоточность в будущих релизах.

С помощью nginx-rtmp-module мне удалось полностью утилизировать 10-гигабитный канал. При этом основной проблемой стала вовсе не прожорливость самого nginx, а необходимость тюнинга сетевой карты и параметров ядра, чтобы software interrupts не съедали 100% CPU.

Ссылки по теме:

RTMP на Википедии
Wowza — официальный сайт
Erlyvideo — официальный сайт
Nginx-rtmp-module — проект на GitHub

Автор: Aecktann

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js