[Python, Обработка изображений, Машинное обучение, Облачные сервисы, Kubernetes] Архитектура облачного волейбольного сервиса

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
11-Ноя-2020 09:31

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

Например, такими:

Теперь, как это все работает.
Технологии
Все написано на python, веб-сервис — Django/Gunicorn.
Интенсивно используются OpenCV и FFMpeg.
База данных — Postgres.
Кэш и очередь — Redis.
Альфа
В самой первой версии было 3 компонента:
  • Front — Веб сервис (Django), с которым взаимодействуют конечные пользователи
  • Videoproc (Vproc) — Ядро алгоритма, python + opencv, которое содержит все алгоритмы треккинга мяча и логику нарезки на розыгрыши
  • Clipper — Сервис генерации видео на основе выхлопа Vproc, используя ffmpeg


Разработка велась локально, я поставил на домашний десктоп Ubuntu, а на нее microk8s и получил маленький Кубернетес-кластер.
Здесь я столкнулся с тем, что кадры, которые видит opencv не очень совпадают с временем, которое видит ffmpeg из-за особенностей кодеков, поэтому высчитать время в оригинальном файле из номера кадра оказалаось невозможно.
Из-за этого пришлось сохранять кадры, что сильно замедлило процесс и потребовало дальнейших архитектурных изменений.
Параллельная обработка
Как уже упоминалось, время обработки в 3 раза превышает время игры. Профайлер показал, что, большая часть времени тратится при записи кадров на диск, сам же разбор кадров примерно в два раза быстрее.
Логично распараллелить эти две работы.
По начальной задумке пока vproc разбирает кадры через opencv, ffmpeg параллельно записывает все на диск, а clipper собирает из них видео.
Но с ffmpeg нашлись две проблемы:
  • Кадры из ffmpeg не идентичны кадрам из opencv (это не всегда так, зависит от кодека видеофайла)
  • Количество кадров в записи может быть слишком большим — например час видео при хорошем fps — это порядка 200K файлов, что многовато для одного каталога, даже если это ext4. Городить разбиение на поддиректории и потом склеивать при компоновке видео — не хотелось усложнять

В итоге вместо ffmpeg появился пятый элемент компонент — Framer. Он запускается из vproc, и листает кадры в том же видеофайле, ожидая пока vproc найдет розыгрыши. Как только они появились — framer выкладывает нужные кадры в отдельную директорию.
Из дополнительных плюсов — ни одного лишнего кадра не эспортируется.
Мелочь, но все таки.
По производительности (на 10-минутном тестовом видео):
Было:
Completed file id=73, for game=test, frames=36718, fps=50, duration=600 in 1677 sec

Стало:
Completed file id=83, for game=test, frames=36718, fps=50, duration=600 in 523 sec + framer time 303

Выигрыш в два раза, очень хорошо. Если писать в несколько потоков, то наверное можно выжать еще чуть. Если хранить кадры в памяти и генерить из них видео через API, то скорее всего можно ускориться значительно.
Digital Ocean
Дальше я стал выбирать хостинг. Понятно, что основные варианты — GKE, AWS, Azure, но многие авторы мелких проектов жалуются на непрозрачное ценообразование и, как следствие, немаленькие счета.
Основная засада здесь — цена за исходящий трафик, она составляет порядка $100/Tb, а поскольку речь идет о раздаче видео, вероятность серьезно попасть очень неиллюзорна.
Тогда я решил глянуть второй эшелон — Digital Ocean, Linode, Heroku. На самом деле Kubernetes-as-service уже не такая редкая вещь, но многие варианты не выглядят user-friendly.
Больше всего понравился Digital Ocean, потому что:
  • Managed Kubernetes
  • Managed Postgres
  • S3 хранилище с бесплатным(!) CDN + 1 TB/месяц
  • Закрытый docker registry
  • Все операции можно делать через API
  • Датацентры по всему миру

При наличии CDN веб-серверу уже не было надобности раздавать видео, однако кто-то должен был это видео опубликовать.
Так в архитектуре появился четвертый компонент — Pusher.

Однако серьезным недостатком оказалась невозможность смонтировать один и тот же диск на несколько машин одновременно.
Сам DO предлагает в таких случаях использовать NFS через выделенный контейнер, но пока решил не заморачиваться, ибо, как упоминалось выше, назревает специальное решение для видео кадров, и если уже городить отдельный контейнер, то для него.
Тем не менее, отсутствие общего диска серьезно повлияло на архитектуру.
Если с передачей загружаемого файла, можно было выкрутиться через S3, то гонять туда-сюда сотни тысяч кадров не выглядело блестящим вариантом.
В итоге, пришлось привязать все стадии обработки конкретной видео к одной ноде, что конечно уменьшило общую масштабируемость системы.
Логи и метрики
Запустив кластер в облаке, я стал искать решение для сбора логов и метрик. Самостоятельно возиться с хостингом этого добра не хотелось, поэтому целью был free-tier в каком-нибудь облаке.
Такое есть не у всех: Модная Grafana хочет $50 в месяц, выходящий из моды Elastic — $16, Splunk даже прямо не говорит.
Зато внезапно оказалось что New Relic, также известный своими негуманными ценами, теперь предоставляет первые 100G в месяц бесплатно.
Видео
Вполне ествественным решением виделось разделить кластер на два node-pool'а:
  • front — на котором крутятся веб-сервера
  • vproc — где обрабатывается видео

Фронтовой пул, понятно, всегда онлайн, а вот процессинговый не так прост.
Во-первых, обработка видео требует серьезных ресурсов (= денег), а во-вторых, обрабатывать приходится нечасто (особенно в стадии зарождения проекта).
Поэтому хочется включать процессинг только, чтобы обработать видео (время обработки — 3x от продолжительности действа).
Кубернетес формально поддерживает autoscale 0, но как именно это реализуется — я не нашел, зато нашлась такая дискуссия на Stack Overflow.
В итоге пришлось нагородить еще один под во фронтовом пуле, единственной задачей которого является посматривать в постгрес иногда и включать/выключать процессинговый пул в зависимости от того, что в базе оказалось.
У DigitalOcean есть неофициальный клиент для питона, но он уже давно не обновлялся, а Kubernetes API там не присутствует в принципе.
Я сделал на коленке клиент для себя, он покрывает процентов десять возможностей, но вдруг кому пригодится для старта.
В итоге диаграмм разрослась вот так:

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

===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_python, #_obrabotka_izobrazhenij (Обработка изображений), #_mashinnoe_obuchenie (Машинное обучение), #_oblachnye_servisy (Облачные сервисы), #_kubernetes, #_digital_ocean, #_django, #_opencv, #_kubernetes, #_python, #_python, #_obrabotka_izobrazhenij (
Обработка изображений
)
, #_mashinnoe_obuchenie (
Машинное обучение
)
, #_oblachnye_servisy (
Облачные сервисы
)
, #_kubernetes
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 18:06
Часовой пояс: UTC + 5