Мой блог
Векторный поиск: деплой моделей без GPU на Triton Inference Server
Перед каждым инженером после создания успешной модели машинного обучения встает закономерный вопрос: как запустить ее в production, чтобы сервис работал быстро и стабильно. Меня зовут Сергей Багров, и сегодня я хочу разобрать практический опыт развертывания векторного поиска на CPU с помощью NVIDIA Triton Inference Server, опираясь на реальный кейс команды MAGNIT OMNI.
Когда ML-модель успешно обучена и поднимает ключевые метрики бизнеса, ее необходимо эффективно «приземлить» в инфраструктуру. При этом важно не просто обеспечить функционирование алгоритма, но и получить из коробки гибкие метрики, высокую скорость ответа и отказоустойчивость, чтобы можно было смело отправляться на заслуженный отдых.


Почему был выбран Triton Inference Server
Долгое время стандартом индустрии для развертывания моделей оставались классические REST-фреймворки, среди которых лидирует FastAPI. Это понятный инструмент с отличной документацией и множеством обучающих материалов, однако он обладает существенными ограничениями в промышленной эксплуатации.
Ограничения стандартных REST-решений
При использовании FastAPI такие инфраструктурные вещи, как динамический батчинг входящих запросов, gRPC-протокол, система кэширования, проверки здоровья (health check) и сбор метрик, приходится реализовывать вручную. Разработчику нужно самостоятельно писать обвязку, тестировать ее и поддерживать в актуальном состоянии.
Кроме того, если первоначальный запуск производился на центральном процессоре, последующий переход на графические ускорители требует серьезной переработки конфигурации драйверов внутри Docker-образа. Но главным узким местом традиционного подхода становится скорость: даже элементарный инференс одного запроса на CPU может занимать порядка 30 миллисекунд, что категорически не подходит для высоконагруженных систем.

Сравнение фреймворков для инференса
Для наглядности можно сопоставить популярные инструменты по ключевым критериям. Например, динамический батчинг в том же FastAPI или BentoML реализуется силами разработчика, тогда как в Triton эта функция встроена нативно. Аналогичная ситуация обстоит с кэшированием ответов, поддержкой gRPC и экспортом метрик для Prometheus.
Альтернативный инструмент BentoML по-своему удобен, но весь процесс инференса там выполняется внутри стандартных процессов Python со всеми вытекающими из этого ограничениями Global Interpreter Lock и дополнительными накладными расходами. Именно поэтому создатели BentoML для максимального ускорения часто рекомендуют использовать внутри своего продукта именно Triton. Учитывая, что в поисковых системах значительная доля запросов регулярно повторяется, встроенный механизм кэширования становится критически важным требованием.
Архитектура и разделение сервисов
Прежде чем переходить к настройке инфраструктуры, стоит разобраться с особенностями самой модели векторного поиска. В качестве базового эмбеддера применяется компактная русскоязычная архитектура BERTA, полученная в результате дистилляции модели FRIDA от SaluteDevices.
Особенности модели и разделение логики
Унаследованная от предшественницы система префиксов («search_query:» и «search_document:») предназначена для реализации асимметричного поиска. Исходя из этого критерия, разработчики разделили общую функциональность на два изолированных микросервиса: отдельно для генерации эмбеддингов поисковых запросов и отдельно для обработки товаров.
Такой подход обусловлен совершенно разными паттернами нагрузки. Онлайн-сервис запросов критически зависит от скорости ответа, поскольку пользователь ждет результат немедленно. В то же время эмбеддинги товарной базы обновляются фоново при изменении каталога, поэтому здесь на первый план выходит общая пропускная способность системы.
Минимизация использования Python
Чтобы максимально повысить производительность, от Python в теле сервиса решили практически полностью отказаться, оставив его исключительно для задач токенизации. Небольшая вспомогательная модель на Python-бэкенде добавляет необходимые префиксы, вызывает токенизатор и передает готовые тензоры дальше.
Основное тело нейросети было сконвертировано в формат ONNX и передано нативному движку onnxruntime. Это позволило полностью исключить написание кастомного кода для инференса: достаточно положить веса модели и конфигурационный файл рядом в репозиторий, а все остальное сервер сделает автоматически.
Тонкая настройка и конфигурация
После подготовки архитектурной базы необходимо правильно настроить параметры работы сервиса через конфигурационный файл модели. Правильная оптимизация позволяет полностью раскрыть потенциал оборудования без использования дорогостоящих видеокарт.
Кэширование и батчевание
Первый важнейший параметр — встроенный механизм кэширования ответов, который может функционировать как в локальной памяти, так и через удаленное хранилище Redis. Для его активации в конфигурации прописывается соответствующий параметр включения, а при старте сервера задается общий объем выделенной памяти.
Для обработки всплесков трафика используется динамическое батчинг-соединение. Система аккумулирует поступающие запросы в пачки заданного размера и выполняет параллельный инференс, что существенно снижает нагрузку на вычислительные ядра.
Управление потоками исполнения
Отдельного внимания заслуживают специфические настройки для бэкенда onnxruntime. Параметр intra_op_thread_count определяет количество потоков для параллельного вычисления отдельного оператора, фактически задавая число ядер для конкретного экземпляра модели.
Второй параметр, inter_op_thread_count, отвечает за независимые операторы граф-модели. При последовательном режиме выполнения устанавливается значение единица, после чего распределяются доступные аппаратные ресурсы между экземплярами модели, токенизацией и системными процессами Triton.
Итоговые результаты и бенчмарки
Практическое внедрение описанного решения на процессорах показало трехкратное превосходство в производительности по сравнению с классическими REST-реализациями. Выделенные вычислительные ресурсы позволили уверенно обрабатывать высокий поток запросов без необходимости задействовать дорогостоящие графические ускорители.
В результате сервис на обычных процессорных ядрах стабильно держит нагрузку свыше одной тысячи запросов в секунду при минимальных задержках. Значительную часть работы берет на себя интеллектуальное кэширование, а всю инфраструктурную сложность удалось свести к лаконичным конфигурационным файлам.
