Как я спас внедрение ML-моделей в Сбере
Был обычный день в Сбере. Я работал DevOps-инженером над платформой ML-моделей. Всё шло своим чередом, пока не пришла задача: перевести модели с Flask на новый асинхронный фреймворк - aiohttp. Старый фреймворк выводили из поддержки, дедлайн горел.
Проблема была не в технологиях. Проблема была в людях. Дата-сайентисты - умнейшие ребята, которые умеют обучать модели. Но они не хотели разбираться в новом фреймворке. Они привыкли к Flask, а асинхронность для них была тёмным лесом. Процесс миграции встал. Никто не двигался. А документации почти не было. Я собирал информацию по кускам: код фреймворка, архитектурные документы, бизнес-требования, функциональные требования. И сверял всё это с реальностью.
Я посмотрел на это всё, вздохнул и сказал себе: ладно. Если не я, то кто? За месяц я разобрался во фреймворке изнутри - изучил чужой код, архитектуру, асинхронные вызовы. Это было непросто, но у меня был опыт с aiohttp - я год изучал асинхронность ещё в 2017 году. Я написал интеграционный код для моделей на Python: обертка модели в новый интерфейс, настройка экспорта кастомных метрик, обработка ошибок, логирование, ретраи. Сначала для одной модели. Потом для трёх. Аналитик использовал мой код как шаблон для тиражирования.
Но это была только половина дела. Корпоративный пайплайн был напичкан проверками: SonarQube, сканеры уязвимостей, проверка стабильности, покрытие тестами. Нужно было понять, как пройти каждый этап. Я разобрался. Фреймворк отдавал метрики, но не все - я добавил кастомные метрики через Fluentd в Prometheus и Grafana. Деплой изначально был полуавтоматическим - нужно было вручную собирать параметры запуска. Я написал мини-пайплайн на Jenkins, который автоматизировал процесс.
Вместе с аналитиком мы гоняли систему и выяснили, что gRPC заявлен в документации, но фактически не работает. Подобрали оптимальные параметры Kafka и потоков.
Система обработала 20 миллионов записей за 40 минут. Я написал код для трёх моделей, передал команде для тиражирования. Проект был спасён. Без моего вмешательства он был бы сорван. Дата-сайентисты бы ещё месяц разбирались с aiohttp, а дедлайн бы прошёл.
Я не стал дата-сайентистом. Я не стал разработчиком. Но я спас внедрение. И это - моя работа.
DevOps - это не только про инфраструктуру. Иногда нужно взять и написать код за других, если это спасает проект. Не бойтесь выходить за рамки роли. Если видите, что команда не может или не хочет - берите ответственность. Главное - довести до результата и передать команде.
#SRE #DevOps #MLOps #Python #Kubernetes #OpenShift #Kafka #HighLoad
· 17.09
Спасибо за вопрос — важный момент. В нашем случае архитектура была такая: фреймворк обеспечивал всю обвязку — приём сообщений из Kafka, HTTP-интерфейс, управление потоками aiohttp. Приложение с моделью крутилось в отдельном поде, а консумер слал к ней HTTP-запрос по сети кластера. То есть инференс не блокировал event loop консумера — он был изолирован в отдельном процессе пода.
Синхронный инференс в event loop — это была бы классическая ловушка, если бы модель крутилась в том же процессе. Но у нас архитектура была разделена: консумер — отдельно, модель — отдельно. Это снимало проблему блокировки.
Количество потоков aiohttp регулировалось, и мы подбирали его под количество партиций Kafka: если ставили 4 репликации — нужно было 4 партиции в топике. Это обеспечивало параллельную обработку.
Моя задача была — интеграция модели в этот фреймворк: обертка, кастомные метрики, обработка ошибок. И проверка, что вся цепочка работает под нагрузкой. На нагрузочном тестировании мы выявили, что gRPC заявлен, но не работает — и подобрали оптимальные параметры Kafka и потоков.
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён