Загрузка и конвертация видео на Rutube: от костылей к мета-программированию

от автора

Как театр с вешалки, видеохостинг начинается с загрузки и конвертации видео. Поэтому, в своей второй статье мы решили остановится именно на этих компонентах платформы. Хорошо, что в стародавние времена не было проблем с финальным форматом (безальтернативный flash в браузере), да и многообразие исходников было не таким, как сейчас — иначе первые годы Rutube были бы еще веселее.

Зато остальные элементы системы загрузки и конвертации сполна компенсировали временное спокойствие.


Детские болезни

Проблемы начинались собственно с «физической» загрузки исходников через uploader.

В 2009 году принимающей стороной служил nginx c nginx-upload-module, который поддерживал актуальные версии веб-сервера и мог корректно отдавать прогресс загрузки файла, но… только в рамках одной машины. А поскольку машин было больше одной (на самом деле, две), прогресс работал ровно через раз.

Файлы после загрузки перекладывались в NFS-шару, а соответствующим роликам в базе проставлялся статус «готов к конвертации». Конвертер скачивал файл с NFS в локальную папку, делал из него что-то типа 700k@360p в формате flv, «накатывал» сверху iflv-индекс и загружал по SSH на сторадж-сервера FileCluster (подробнее о том, что такое FileCluster можно прочитать тут).

Заметки на полях: Первой ошибкой было полагаться на прогресс nginx-upload-module в памяти одного процесса.
Даже переписав uploader на Twisted, мы не получили желаемой стабильности — пришлось потратить много времени на настройку аппаратной балансировки, чтобы прогресс не отваливался из-за запросов на другой сервер. Казалось бы, sticky sessions решают проблему, но нет — пробовали и это — встает вопрос дисбаланса нагрузки. Сейчас прогресс загрузки периодически скидывается в Redis и доступен с любой машины.

Тучи сгущаются

С ростом числа роликов у планировщика конвертера начались проблемы: организация очередей конвертации на статусах основной таблицы сайта (track) стала массово создавать дедлоки и таймауты транзакций.

Как раз в этот момент в поле зрения появился сервер очередей Beanstalkd, и возникла идея использовать его в системе конвертации. В новой версии аплоадера, по завершении загрузки, ставилась задача в beanstalkd. Задачу принимал один из свободных воркеров, и, в тесном сотрудничестве с БД сайта, прогонял ролик через алгоритмы обработки видео.

Заметки на полях: Теперь мы знаем, что Beanstalkd не самый хороший выбор для обеспечения надежности обработки задач. Кроме бинлога, у него нет средств бекапа и дублирования, да и сам бинлог «с сюрпризами».

Например, простейший DOS в случае нагруженного сервера можно организовать, положив одну (!) задачу в очередь, которую не будет никто слушать. Бинлог при этом начнет разрастаться до тех пор, пока не займет все доступное место, или пока «Та Самая Задача» не будет удалена из очереди. Наш рекорд — 170GB. А ведь всего лишь умудрились сложить в «рабочую» очередь задачу в статусе Buried — отложена навсегда. Если бы beanstalk «умер», с таким бинлогом он вряд ли бы поднялся.

Тем временем, жизнь не стояла на месте и приносила как новые форматы и устройства просмотра, так и новые виды исходных файлов. В 2011 году встал вопрос о переходе с RTMP на HDS, и соответственно, с оригинального формата iflv на mp4. В систему был добавлен «деиндексатор», делающий из iflv нормальный «машиночитаемый» flv, который потом перепаковывался в mp4.

Заметки на полях: UGC-контент это вообще готовый набор тестов: видео без аудио, аудио с тамбнейлами и просто «битые» файлы.

Если раньше оригинальность ограничивалась лишь flash-ролики а-ля «масяня» и презентациями PowerPoint, то сейчас все гораздо веселее. Попадаются файлы, в метаданных которых были одновременно указаны смещение аудио относительно видео и видео относительно аудио — причем разные!

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

Совет: если вам и такого экстрима недостаточно — выступите организатором творческого видео конкурса.

Результатом изменения окружающей действительности стало сильное разрастание кодовой базы, занимающейся обходом этих косяков особенностей.

Спасительное мета-программирование

Весь объем костылей и логических веток вскоре перестал влезать в голову разработчика в виде кода, и был переписан с использованием мета-программирования на графах.

Рассказывает tumbler:

— Вообще, дело было даже не так. Сначала в редакторе yEd был вручную нарисован весь алгоритм обработки файла: просто чтобы понять и -простить-осознать. В результате получился большой XML файл, по сути являющийся описанием направленного графа с привязанными к вершинам и ребрам текстовыми данными.

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

Аргументы функций тоже аккуратно поместились на графе (в вершинах другого вида).

Пример кусочка графа

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

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

Но это все еще «цветочки» по сравнению с вызовами, полученными системой загрузки и конвертации от Департамента лицензирования: поддержка различных DRM; кастомные настройки параметров и приоритетов конвертации; переконвертация существующих роликов, запись VOD из LIVE-потоков; загрузка файлов в профессиональных форматах типа mxf (в сопровождении файла с разметкой логических пауз, которые нужно удалить при конвертации); отправка результатов конвертации не только на хранилища Rutube, но и на внешние архивные сервера; добавление логотипов в видеопоток. А у творческого конкурса начался 8 сезон, и изысканные эксперименты в форматах исходников продолжились.

Стало понятно, что одним мета-программированием уже не спастись — нужно больше рефакторинга!

Текущая архитектура

На данный момент из конвертера выпилена всякая административная логика и он занимается непосредственно конвертацией. А администрированием процессов конвертации занимается сервис DUCK — Download, Upload, Convert King.

DUCK по требованию разных подсистем создает сессии, ставит задачи в celery, следит за работоспособностью и загрузкой серверов, а главное, обрабатывает все события от задач — в основном, для отслеживания возникающих ошибок. Получился вообще отдельный сервис, которому можно сказать: «Эй, чувак, возьми файлик «тут». Сделай из него вот «это» и сложи «сюда». Как сделаешь, дерни «эту» ссылку».

Получив задачу, конвертер запускает на серверах обработки воркеры DUCK и «заменяет» пустые тела celery task-ов кодом обработки.

К примеру, код задачи «duck.download» занимается загрузкой по FTP/HTTP, следит за ошибками и таймаутами. Код «duck.encode.images» занимается созданием скриншотов из исходных файлов.

Все эти задачи завернуты в «chain» и «chord» из модуля «celery.canvas», а базовый класс «celery.Task» приобрел дополнительную функциональность: при выполнении некоторых условий длинный chain может быть пропущен до финальной его части — «duck.cleanup»; это позволяет обойтись без прохождения всех задач цепочки, если к примеру, на этапе создания видео выяснилось, что файл — битый.

С другой стороны, все неизвестные ошибки автоматически попадают в очередь WTF. Она разгребается разработчиками (обычно таких случаев мало — зато они интересные): и либо превращается в баги в багтрекере, либо задачи выполняются заново с начала цепочки (удобно, к примеру, если сервер, на котором обрабатывался файл, «умер»).

DUCK следит за прохождением задач с помощью «камер» celery: сессия конвертации меняет статус в БД в зависимости от событий, которые пришли в «камеру»; автоматически отрабатываются ошибки и прогресс обработки задач. При этом наиболее важные события, такие, как регистрация факта, что обработанный файл успешно сохранен в FileHeap, делаются через RPC: так файлы точно не потеряются.

DUCK также хранит настройки конвертации для разных пользователей. Это могут быть как настройки приоритетов (например, хайлайты из live спортивных трансляций нужно сделать доступными для просмотра незамедлительно, а заливка архива прошлых лет может проходить в фоне несколько недель); так и ограничения по количеству находящихся в обработке и конвертации роликов. В настройках могут быть указаны кастомные параметры конвертации каждого из качеств (нужно 4К? — Welcome!); необходимость обрезки «черных полос» (частая проблема «телевизионных» исходников), нормализации звука и добавления логотипа в видеопоток, автоматическое «вырезание» ненужных фрагментов.

Конечно мы хотели бы обернуть возможности пользовательского редактирования фронтендом и сделать доступными для всех (понемногу занимаемся этим в рамках проекта Dashboard), но пока ближайшая цель — значительно ускорить конвертацию. По предварительным оценкам — почти в 10 раз. О результатах расскажем!

ссылка на оригинал статьи http://habrahabr.ru/post/270223/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *