Простое управление нагрузкой, например при декодировании видео в видеохостингах и подобных проектах

в 12:30, , рубрики: видеохостинг, высокая производительность, Программирование, системное программирование, метки:

Очень тривиальное, но боевое решение, где-то на грани Unix Way. Я покажу только метод решения, без привязки к каким-то конкретным средам. Реализуйте по своему вкусу и убеждениям.

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


Итак, на какой-то момент у вас уже есть некая CMS, которая умеет не только показывать видео, но и загружать видео-файлы. Конечно, ваша CMS написана на скриптовом ЯП, в котором доступны строковые операции, работа с файлами и вызовы ОС. Для решения задачи этого достаточно.

Добавляем функцию в CMS, выполняемую после успешной загрузки видео:
— переместить и переименовать файл, если это необходимо, записать новые данные в БД
— создать текстовый файл – скрипт на BASH, сохранить его со случайным именем в директорию выше корня документов, при необходимости записать путь и имя в БД

Инструкции в скрипте:
— создать файл-флаг {unique}.progress, означающий выполнение задачи в текущем времени
— запустить кодирование (или другой ресурсоемкий процесс, если это не хостинг)
— удалить файл-флаг {unique}.progress
— создать файл с отчетом, если это необходимо, или направить данные CMSке, например через wget
— самоудалиться, если это необходимо

Актуальный пример (уже с avconv вместо ffmpeg)

#!/bin/sh
: > {PROGRESS}.progress
avconv -i {ORIGINAL} -vf "movie={WATERMARK} [wm];[in][wm] overlay=5:5 [out]" -ab 128k -vcodec libx264 -vb 1000k {RESULT}.mp4
avconv -i {ORIGINAL} -vf "movie={WATERMARK} [wm];[in][wm] overlay=5:5 [out]" -ab 128k -vcodec libtheora -acodec libvorbis -vb 1000k {RESULT}.ogv
rm {PROGRESS}.progress

Естественно, CMS должна подменивать {параметры} на конкретные значения.

Если запуск обработки будет запускаться через cron – используйте абсолютные пути. Выносите пути до директорий в конфигурацию CMS.

Простой тест

На конкретной машине запускаете руками тесты: один поток, два потока, три потока одновремено и так далее. Смотрите глазами на AVG (например, через top). Так вы сможете просто убедиться, сколько параллельных процессов может выполняться в конкретном окружении. Большая часть задач не существенно отличаются в ресурсоемкости, в зависимости от исходных данных. Именно – отличия есть, но они не существенные, и в большинстве случаев ими можно пренебречь.

Таким образом, возможно получить параметр, для каждой конкретной системы – сколько искомых процессов может одновременно выполняться на машине без риска перегрузки.

Диспетчеризация задач с управлением нагрузкой

Вариант А. Диспетчеризация “штатными” средствами CMS

Предложу один из возможных вариантов решения. Разумеется, вы можете программировать, как сочтете нужным, предложенный метод ни в чем не лучший и вовсе не панацея – я показываю его, просто чтобы объяснить технологию.
1. Метод get_progress(). Получить количество процессов, выполняющихся в настоящем времени (например, посчитать количество progress-файлов в директории с файлами-флагами и сохранить в свойство класса)
2. Метод run_task(). В зависимости от максимально разрешенного количества одновременно выполняющихся процессов (вы же сохранили этот параметр в конфигурацию CMS?), принять решение – запускать или не запускать новый процесс
3. Метод tasks_progress(). Выборкой из БД получить “задания” на обработку, со статусами “ожидает обработки” и “в процессе”. При наличии последних – исследовать progress-файлы и внести в БД изменения. При наличии первых – выбрать по какому-то принципу, на ваше усмотрение, и запустить
4. Метод run_task(). Запуск процесса. Чтобы CMSка не подвисала, ожидая окончания выполнения долгой ресурсоемкой операции, можно сделать так, например для PHP

$command = $path.$script.' > /dev/null 2>/dev/null & ';
exec($command);

Направление вывода BASH-скрипта в /dev/null приведет к тому, что интерпретатор PHP не будет ожидать ответа команды, и в штатном режиме продолжит и корректно завершит свое исполнение. Что и требовалось доказать.
Как объединить методы и как именно запрограммировать – вам виднее. Задачка простая, поэтому обойдемся без воды.

Вариант Б. Диспетчеризация через cron

Например, ежеминутно cron запускает скрипт, который:
— знает ограничение на максимальное количество одновременно выполняемых процессов
— исследует количество процессов, запущенных в настоящее время, просто подсчитав количество progress-файлов в соответствующей директории
— ищет скрипты-задачки в соответствующей директории, для выполнения
— принимает решение, и запускает скрипты
В этом случае необходимо сделать две модификации:
— первой инструкцией скрипта должна быть самоликвидация rm {SCRIPTNAME}. Это никак не скажется на его выполнении – он запустится, уже будучи “загруженным” в ОЗУ, и только лишь удалит текстовый файл
— пути должны быть абсолютными (удобно прописывать их в конфигурации CMS)

Развертывание

На боевой машине
1. Ставим опыт, исследуя нагрузку на процессор и ОЗУ в зависимости от количества запущенных задач.
2. Принимаем решение о допустимой максимальной нагрузке, исходя из загруженности сервера другими задачами. Например – 20%, 40%, 50%, 70% и т.д.
3. Получаем вполне конкретное число – максимально допустимое количество одновременно работающих процессов. Например – 1, 2, 4, 8, 16 и т.д.
4. Вносим данные в конфигурацию CMS
5. Запускаем задание cron, если это необходимо.

Указанный метод успешно применяется на нескольких десятках видеохостингов и подобных проектов.

Автор: customtema

Источник

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


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