Архитектура Облачного Волейбольного Сервиса

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

Возможно, общественное сознание найдет недостатки в архитектуре и подтолкнет к лучшим решениям.

Краткое описание функционала:

  • пользователь загружает видео волейбольного матча
  • один умный алгоритм распознает мяч в кадрах
  • другой умный алгоритм выделяет ничьи
  • розыгрыши компилируются в отдельные видеофайлы
  • файлы с розыгрышами собраны в дайджест всей игры
  • все видео загружаются в облако
  • пользователи смотрят/скачивают/делятся клипами с самыми крутыми розыгрышами
Например, вот так:

Архитектура облачного волейбольного сервиса

Теперь как все это работает.

Технологии

Все написано на питоне, веб-сервис — Django/Gunicorn. OpenCV и FFMpeg активно используются.

База данных — Постгрес.

Кэш и очередь — Redis.

Альфа

Самая первая версия имела 3 компонента:
  • Передний — Веб-сервис (Django), с которым взаимодействуют конечные пользователи
  • Видеопроцесс (Впрок) — Ядро алгоритма python + opencv, содержащее все алгоритмы отслеживания шаров и логику разрезания на ничью.

  • Клипер — Сервис генерации видео на основе вывода Vproc с использованием ffmpeg.


Архитектура облачного волейбольного сервиса

Разработка велась локально, я установил Ubuntu на домашний рабочий стол, а на нем микрок8с и получил небольшой кластер Kubernetes. Тут я столкнулся с тем, что кадры, которые видит opencv, на самом деле не совпадают со временем, которое видит ffmpeg из-за особенностей кодеков, поэтому вычислить время в исходном файле по номеру кадра оказалось невозможно.

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



Параллельная обработка

Как уже упоминалось, время обработки в 3 раза превышает время игры.

Профилировщик показал, что большая часть времени тратится на запись кадров на диск, а сам парсинг кадров происходит примерно в два раза быстрее.

Логично провести параллель этих двух работ. По первоначальной задумке, пока vproc разбирает кадры через opencv, ffmpeg одновременно записывает всё на диск, а клиппер собирает из них видео.

Но с ffmpeg было две проблемы:

  • Кадры из ffmpeg не идентичны кадрам из opencv (это не всегда так, в зависимости от кодека видеофайла)
  • Количество кадров в записи может быть слишком большим — например, час видео с хорошим fps — это около 200К файлов, что очень много для одного каталога, даже если это ext4. Разделил его на подкаталоги и потом объединил при компоновке видео - не хотелось усложнять
В результате вместо ffmpeg появился пятый элемент компонента — Framer. Он запускается из vproc и прокручивает кадры в одном и том же видеофайле, ожидая, пока vproc найдет ничьи.

Как только они появляются, фреймер загружает необходимые кадры в отдельный каталог.

Дополнительным преимуществом является то, что не экспортируется ни один лишний кадр.

Мелочь, но всё же.

Производительность (на основе 10-минутного тестового видео): Был:

Завершенный файл с id=73, для игры=test, кадров=36718, fps=50, длительности=600 за 1677 сек.

Стал:
Идентификатор завершенного файла=83, для игры=тест, кадров=36718, кадров в секунду=50, длительности=600 за 523 секунды + время кадра 303
Дважды выиграть – очень хорошо.

Если писать в несколько тем, наверное, можно выжать немного больше.

Если хранить кадры в памяти и генерировать из них видео через API, то, скорее всего, можно существенно ускориться.



Цифровой океан

Потом я начал выбирать хостинг.

Понятно, что основные варианты — GKE, AWS, Azure, но многие авторы небольших проектов жалуются на непрозрачное ценообразование и, как следствие, довольно большие счета.

Основная проблема здесь — цена на исходящий трафик, она составляет около $100/Тб, а поскольку речь идет о раздаче видео, вероятность серьёзного удара очень мала.

Тогда я решил присмотреться ко второму эшелону — Digital Ocean, Linode, Heroku. На самом деле Kubernetes-as-service уже не такая уж редкость, но многие варианты выглядят неудобными для пользователя.

Digital Ocean мне понравился больше всего, потому что:

  • Управляемый Kubernetes
  • Управляемый Postgres
  • Хранилище S3 с бесплатным(!) CDN + 1 ТБ/мес.

  • Частный реестр докеров
  • Все операции можно выполнять через API
  • Дата-центры по всему миру
Благодаря CDN веб-серверу больше не нужно было обслуживать видео, но кто-то должен был его публиковать.

Так в архитектуре появился четвертый компонент — Pusher.

Архитектура облачного волейбольного сервиса

Однако серьезным недостатком оказался невозможность монтировать один и тот же диск на нескольких машинах одновременно .

ДЕЛАЙ сам предложения в таких случаях используйте NFS через выделенный контейнер, но я пока решил не заморачиваться, потому что, как уже говорилось выше, назревает специальное решение для видеокадров, и если у вас уже есть отдельный контейнер, то и для него.

Однако отсутствие общего диска сильно повлияло на архитектуру.

Если передачу загруженного файла можно было осуществить через S3, то пересылка сотен тысяч кадров туда и обратно не представлялась блестящим вариантом.

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



Журналы и метрики

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

Я не хотел возиться с хостингом всего этого самостоятельно, поэтому целью был бесплатный уровень в каком-нибудь облаке.

Не у всех такое есть: Модный Grafana хочет $50 в месяц, вышедший из моды Elastic — $16, Splunk даже прямо не говорит. Но вдруг выяснилось, что New Relic, также известная своими негуманными ценами, теперь бесплатно предоставляет первые 100G в месяц.



видео

Казалось вполне естественным решением разделить кластер на два пула узлов:
  1. фронт — на котором крутятся веб-серверы
  2. vproc — где обрабатывается видео
Передний пул, конечно, всегда онлайн, но с пулом обработки все не так просто.

Во-первых, обработка видео требует серьезных ресурсов (= денег), во-вторых, его приходится обрабатывать нечасто (особенно на начальном этапе проекта).

Поэтому я хочу включить обработку только для обработки видео (время обработки в 3 раза превышает продолжительность действия).

Kubernetes формально поддерживает автомасштабирование 0, но как именно это реализовано, мне не удалось найти, но я нашел.

Это обсуждение переполнения стека .

В результате мне пришлось добавить в передний пул еще один под, единственная задача которого — иногда смотреть в postgres и включать/выключать пул обработки в зависимости от того, что было в базе данных.

DigitalOcean имеет неофициальный клиент для Python , но он давно не обновлялся, а API Kubernetes там вообще не присутствует. Я сделал это на колене клиент для меня это охватывает процентов десять возможностей, но вдруг кому-то понадобится для начала.

В итоге диаграмма выросла вот так:

Архитектура облачного волейбольного сервиса



DevOps

Несмотря на большое разнообразие инструментов CI/CD, не было ничего удобнее в разработке, чем Jenkins. А действия Github идеально подходили для управления DigitalOcean.

Ссылки

Теги: #Машинное обучение #python #облачные сервисы #Kubernetes #Обработка изображений #django #OpenCV #Digital Ocean
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.