Я работаю в аутсорсе, где главный принцип можно описать фразой «продавай много, делай быстро». Чем быстрее сделаем, тем больше заработаем. И, желательно, чтобы всё работало не на костылях и соплях, а с приемлемым уровнем качества. Я расскажу о своём опыте, когда за короткий срок нужно было разработать промо-сервис.
Дано: root-аккаунт на AWS, отсутствие ограничений по выбору стека технологий, один бэкендер, и один месяц на разработку.
Задача: реализовать промо-сервис, где пользователи загружают от одного до четырёх видео длительностью от одной до четырёх секунд, которые потом встраиваются в оригинальный видеоряд. То есть, подменяем фрагменты оригинального видео (заставка сериала) на пользовательские. Киллер-фича — возможность отправить своё имя, которое в виде красивого текста наложится на соответствующий фрагмент видео. Кроме того, пользователь может загружать видео длиной от 4 до 30 секунд, и на стороне сервиса оно обрежется до 4 секунд.
Решение
Писать свой велосипедный сервис в такие сжатые сроки — так себе затея. Кроме того, чтобы сервис справлялся с нагрузками и все желающие получили заветное видео, потребуется инфраструктура. И желательно не с ценником от самолёта. Поэтому сразу ориентируемся на готовые решения с минимальной кастомизацией.
Стандартное решение для работы с видео — FFmpeg, кроссплатформенная консольная утилита, которая через аргументы позволяет и нарезать, и накладывать звук. Дело за малым — написать обёртку и выпустить её в жизнь. Пишем прототип, который склеивает два видео, и… начинается самое интересное. Библиотека на .NET Core 2, должна крутиться на любой виртуалке, поэтому берём инстанс AWS EC2 и всё заработает
FFmpeg хоть и упрощает задачу, но для реально работающего решения нужно создать ЕС2 инстанс, спроектировать для него сетевую инфраструктуру, включая Load Balancer. Простая задача по деплою с нуля «немного» усложняется, а инфраструктура начинает требовать деньги немедленно — каждый час с клиентского счёта снимается сумма за рантайм.
Наш сервис не предполагает Long-Running процессов, не требует большой и жирной реляционной базы данных и прекрасно укладывается в событийную архитектуру с цепочкой вызовов микросервисов. Решение напрашивается само собой — мы можем отказаться от ЕС2 и реализовать true-serverless приложение, наподобие стандартных Image Resizer на базе AWS Lambda.
Кстати, несмотря на явную нелюбовь разработчиков AWS к .NET, они поддерживают .NET Core 2.1 в качестве рантайма, что даёт полный спектр возможностей для разработки.
И вишенка на торте — AWS предоставляет отдельный сервис для работы с видеофайлами — AWS Elemental MediaConvert.
Суть работы невероятно проста: берём S3-ссылку на исходящее видео, через AWS Console, .NET SDK или просто JSON пишем, что хотим сделать с видео и вызываем сервис. Он сам реализует очереди для обработки входящих запросов, сам выгружает результат в S3 и, самое главное, генерит CloudWatch Event на каждую смену статуса. Это позволяет нам реализовать лямбда-триггеры на завершение процессинга видео.
Примерно так выглядит финальный вариант архитектуры
Весь бэкенд размещается в двух лямбдах. Ещё одна — для ротации вертикальных видео, поскольку такая работа не может быть выполнена за один проход.
Наложение текста выполнено через отрисовку прозрачного изображения на лету в соответствии с разрешением видео. Библиотека SixLabors.ImageSharp прекрасно подходит для данной цели, и проблемы утечек памяти элегантно обходятся жизненным циклом лямбды.
Фронт в виде SPA-приложения, написанного на JS и скомпиленного через pug, разместим в публичной S3 корзине. Для загрузки самих видео нам не нужен никакой серверный код — достаточно открыть REST-эндпоинты, которые нам предлагает S3. Единственный момент — не забываем настроить политики и CORS.
Подводные камни
- AWS MediaConvert по какой-то неведомой причине накладывает звук только на каждый видеофрагмент по отдельности, а нам нужна задорная песня из заставки целиком.
- вертикальные видео нужно обрабатывать отдельно. AWS не любит чёрные полосы и кладёт ролики на 90°.
Изи катка
Несмотря на всю красоту Stateless, необходимо отслеживать, что требуется сделать с видео: склеить или наложить звук на уже готовый видеоряд. К счастью, MediaConvert поддерживает передачу метаданных через свои Job, и мы всегда можем применить простой флаг по виду “isMasterSoundJob”, распарсив эти метаданные на любом этапе.
Serverless отлично позволяет работать NoOps — подходом, который предполагает ненужность отдельной команды, отвечающей за инфраструктуру проекта. Поэтому дело было за малым — разворачиваем решение на AWS без участия сисадминов, которым всегда и так есть чем заняться.
А чтобы всё это ускорить, максимально автоматизируем деплой скриптом на AWS CloudFormation, позволяющим деплоить одной кнопкой прямо из VS. В итоге, файл на 200 строк кода позволяет выкатить готовое решение, хотя и синтаксис CloudFormation с непривычки может шокировать.
Итого
Serverless — не панацея. Но сильно облегчит жизнь в ситуациях с тремя лимитами: «ограниченные ресурсы—короткий срок—мало денег».
Характеристики приложений, которым подходит Serverless
- без Long-Running процессов. Хард лимит API Gateway — 29 секунд, хард лимит лямбды — 15 минут;
- описывается Event-Driven архитектурой;
- разбивается на слабосвязанные компоненты по типу SOA;
- не требует большой работы со своим состоянием;
- написано на .NET Core. Для работы с .NET Framework по-прежнему потребуется как минимум Docker с соответствующим рантаймом.
Преимущества Serverless-подхода
- снижает затраты на инфраструктуру;
- снижает затраты на доставку решения;
- автоматическая масштабируемость;
- разработка на острие технического прогресса.
Недостатки, на конкретном примере
- Распределённый трейсинг и логирование — частично решается через AWS X-Ray и AWS CloudWatch;
- неудобная отладка;
- Cold Start при отсутствии нагрузки;
- User-hostile интерфейс AWS — универсальная проблема :)
Комментарии (10)
random1st
23.04.2019 13:50Хард-лимит лямбды — 15 минут кстати. Вызов API Gateway опять же стоит денег. Плюс тотальный vendor-lock. Плюс в статье не посчитана стоимость в принципе — на каком объеме работает такое решение, на каком serverless становится невыгоден. Разворачивать подобное через UI — это в корне неверное решение для продакшена, а разворачивать эту всю катавасию CloudFormation или Terraform то еще. Паблик S3 — халявный дропбокс для кого-то, все равно нужен фронт, иначе есть риск тупо влететь на деньги. C учетом всего этого решение на EC2/ECS не выглядит затратнее, особенно с учетом возможности кастомизации конвертации и отсутствия vendor-lock.
снижает затраты на инфраструктуру — только если график нагрузки очень неравномерный
снижает затраты на доставку решения — сомнительно
автоматическая масштабируемость — вот это есть, но опять же, вопрос конкарренси лямбд в аккаунте
разработка на острие технического прогресса — no commentsBassist067 Автор
23.04.2019 15:15- За лямбду спасибо, давно не смотрел лимиты.
- Вендор-лок был обговорен, клиент согласен.
- Разворачивал всё через CloudFormation, работает норм.
- Паблик с3 тоже не понравился, но до клиента донесли. При необходимости можно через SignedUrl получить
- Приложение не рассчитано на непрерывную работу и стандартное сравнение «Нам нужно держать 100 реквестов в секунду», где есть смысл в ЕС2. Здесь как раз предполагается Burst
- Инфраструктура Serverless таки значительно проще
а так, спасибо за камент — познавательно.
valis
23.04.2019 15:14Сколько времени на Cold Start у вас уходит (если не секрет)?
Bassist067 Автор
23.04.2019 15:29Бывает, что 15 секунд — если мы говорим про первый запуск после деплоя. Дальше незаметно было, хотя надо потестить ещё.
DrAndyHunter
> реализовать промо-сервис, где пользователи люди загружают от одного до четырёх видео длительностью от одной до четырёх секунд, которые потом встраиваются в оригинальный видеоряд.
А что это означает? Это совместное создание «кино»? Я просто не понял: «потом встраиваются в оригинальный видеоряд»
Bassist067 Автор
Идея довольно простая — мы берём оригинальный видос, разрезаем его и заменяем фрагменты из него на пользовательские видео. Логика простая — считаем, сколько видео нам прислали и подменяем соответствующее количество фрагментов из оригинального видео. Например, всего в заставке 4 персонажа, пользователи прислали два видео. Подменяем их, и получаем результат, где два видео с пользователем, а два с оригинальными актёрами :)
sim3x
Un_skipable ads — пресловутое джойказино, только теперь не только аудиорядно и видео
Bassist067 Автор
Кстати, шутка была бы неплохой шуткой, но AWS Elemental MediaConvert действительно даёт возможность встроить любую непроматываемую рекламу! У них это идёт отдельной настройкой, и, в принципе, при желании, можно было бы поднять целую пиратскую CDN на их мощностях — техническая возможность есть.
Вот только AWS моментально заблокирует за такие фокусы :)
sim3x
Кстати, а какая скорость получилась в итоге?
Сколько времени сервис будет жевать (вставлять, перекодировать) стандартное видео в вакууме?
Bassist067 Автор
В итоге, видео длиной 44 секунды собирается примерно 40 секунд. Очевидно, нам не нужно каждый раз разрезать один и тот же видос, поэтому я нарезал фрагменты заранее и в первой лябмде просто собираю куски в нужном порядке. Если посмотреть трейс по X-Ray (тема для отдельной статьи), оказывается, большая часть времени уходит на то, чтобы отрисовать картинки с неймтегами и загрузить их в S3.
Сам MediaConvert работает на удивление быстро.