Хочу поделиться своим небольшим опытом реализации распространения видеоконтента.
Так
Есть сервис по распространению видеоконтента смотреть (т.е.скачивание не предусмотрено).
При этом весь контент разделен на 2 категории: 1 — дается целиком (весь файл)/пауза, перемотка вперед и назад; 2 - предоставляется как один «виртуальный файл» вида [конец первого файла]+[определенное количество полных файлов]+[начало последнего файла].
Формат — mpegts, каждый набор кодируется одинаково, поэтому части можно просто склеить.
Эти две категории логически различны (совершенно разные вещи), имеют явно разные URI и физически расположены в разных местах.
Как первоначально предлагалось
Комбинация Nginx+apache. Первая категория — банальная раздача контента в nginx с небольшой настройкой.Вторая часть выполняется через скрипт apache-php с использованием цикла.
где $fp — указатель на файл, где функция fseek() выполняется там, где это необходимо.while(!feof($fp)){ .
echo fread($fp, $buf) .
}
Что мне не понравилось
Как оказалось, nginx не очень подходит для раздачи статических файлов с большим количеством запросов диапазона байт (а именно это те запросы, которые в основном поступают при просмотре онлайн).Невозможно использовать AIO для обслуживания таких запросов.
В результате к диску и к клиентам образуется большая очередь, просмотр видео часто сопровождается «тормозами».
Задавать большое количество буферов бесполезно — это просто трата памяти.
Я попробовал последнюю версию nginx (на данный момент 1.12.2), и --with-file-aio, и --with-threads, и еще много чего.
Никакого эффекта я не получил.
Ну, ссылка «echo fread()» в PHP тоже весьма сомнительна.
Вывод fread идёт в промежуточный буфер php и соответственно скрипт потребляет памяти не меньше этого буфера.
Если читать файл небольшими кусочками, увеличивается нагрузка на процессор и снижается скорость загрузки.
Если читать большими кусками, то на каждый запрос тратится слишком много памяти.
Что произошло в конце
Ну, во-первых, я отказался от Apache. Вместо этого php5-fpm. Это дало существенный прирост производительности (скорости отклика) + снижение потребления памяти.
Первая категория
контент, ради эксперимента решил попробовать отдать его вместе со своим сценарием.
В нгинксе: location ~* /media/.
*\.
* {
fastcgi_pass unix:/var/run/php5-fpm.sock;
include /etc/nginx/sites-available/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/m_download.php;
root /var/www;
send_timeout 1h;
}
Я не буду перечислять m_download.php полностью.
Основной функционал: fpassthru($fd);
где $fd — указатель на файл.
Сначала, конечно, нужно разобрать заголовок HTTP_RANGE, открыть файл и установить в нем смещение.
fpassthru() возвращает файл «от текущего до конца».
В данной ситуации это было вполне уместно.
Все игроки играют правильно.
К моему великому удивлению, именно этот метод подачи дал мне нужный мне результат. Очереди на диск нет (точнее используется системный, но с моим SAS-3 12Гб/сек и жду<10ms it’s generally good).
Accordingly, there is no waiting for the request to be processed. The file upload speed (if downloaded) is about 250 Mbit/s. The “brakes” for clients have completely disappeared. В то же время использование памяти значительно уменьшилось, следовательно, больше осталось для файлового кэша.
Сам скрипт при выполнении потребляет около 0,5 МБ собственной памяти.
Исполняемый код по-прежнему существует в памяти в единственном экземпляре, поэтому его размер не имеет значения.
Вторая категория
(вот тут нужно собрать воедино несколько кусков разных файлов) тоже изменилось.Я отказался от ссылки «echo fread()».
К сожалению, в PHP нет функции прямого вывода произвольного фрагмента файла.
fpassthru() не имеет параметра «сколько выводить», он всегда выводит «до конца».
Я попытался вызвать систему dd с помощью passthru().
Те.
: passthru('/bin/dd status=none if='.
$fffilename.' iflag="skip_bytes,count_bytes" skip='.
$ffseek.' count='.
$buf_size);
И.
о чудо! Потребление памяти скриптом чуть больше 0,5 Мб, размер буфера можно установить любой (на память это не влияет).
Скорость отдачи (с буфером 4 МБ)… свистит (те же 250 Мбит/с).
Вот история.
В результате нам пришлось прекратить распространение контента, используя только nginx. Он используется, но только для перенаправления запросов на php5-fpm. Короче говоря, мое ИМХО: nginx хорошо рендерит статические файлы, но плохо читает с диска.
Никогда бы не подумал, что распространение файлов через PHP-скрипт может быть более эффективным.
Ну и добавлю, что искал какой-нибудь httpd с AIO для запросов диапазона байтов «из коробки».
Вроде Lighttpd версии 2 это умеет, но версия пока нестабильная.
Больше ничего подходящего не нашел.
Теги: #Nginx #php #обмен файлами
-
Понимание Пакета Go: Io
19 Oct, 24 -
Проект Перевода «Погружение В Python 3»
19 Oct, 24 -
О Том, Как Устроен Хабрахабр
19 Oct, 24