Оптимизация сервисных точек для развертывания модели в производственной среде

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

Стратегии оптимизации делятся на три категории:

Когда оптимизировать конечную точку

При возникновении любого из следующих сценариев рекомендуется оптимизировать конечную точку службы моделей.

  • Большой объём запросов: ваше приложение отправляет более 50 тысяч запросов в секунду (QPS) на одну конечную точку
  • Требования к задержке: Ваше приложение требует времени отклика менее 100 мс
  • Узкие места при масштабировании: конечные точки сталкиваются с очередью или возвратом ошибок HTTP 429 во время всплеска трафика
  • Оптимизация затрат: Вы хотите снизить затраты на обслуживание, сохраняя при этом целевые показатели производительности
  • Подготовка к продакшену: вы готовитесь перейти от разработки к производственным нагрузкам

Оптимизации инфраструктуры

Оптимизация инфраструктуры улучшает маршрутизацию сети, поведение масштабирования и вычислительные ресурсы.

Оптимизация маршрутов

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

Преимущества в производительности:

Функция Ограничение стандартной конечной точки Ограничение оптимизированной конечной точки маршрута
Запросы в секунду (QPS) на рабочую область 200 50 000+ (обратитесь в Databricks для более высоких лимитов)
Конкуренция клиентов для каждой рабочей области 192-1024 (зависит от региона) Нет явного ограничения (ограничено выделенной параллельностью)
Подготовленная параллельность для конечной точки для каждой обслуживаемой сущности 1,024 1 024 (свяжитесь с Databricks для более высоких лимитов)

Когда использовать оптимизацию маршрутов:

  • Рабочие нагрузки, требующие более 200 QPS
  • Приложения с строгими требованиями к задержке (накладные расходы на под 50 мс)
  • Рабочие развертывания, обслуживающие несколько одновременных пользователей

Это важно

Оптимизация маршрутов доступна только для конечных точек обслуживания пользовательских моделей. API-интерфейсы модели Foundation и внешние модели не поддерживают оптимизацию маршрутов. Маркеры OAuth необходимы для проверки подлинности; личные маркеры доступа не поддерживаются.

См. Оптимизация маршрутов для конечных точек обслуживания для инструкций по настройке и Запрос конечных точек обслуживания, оптимизированных по маршруту для получения сведений о запросах.

Выделенная одновременность

Выделенная параллельность определяет количество одновременных запросов, которые может обрабатывать точка доступа. Настройте выделенную конкуренцию на основе ваших ожиданий по QPS и задержке.

Рекомендации по конфигурации:

  • Минимальная параллельность: Установите достаточно высокий уровень, чтобы обрабатывать базовый трафик без очередей
  • Максимальная параллельность: установите достаточно высоко, чтобы справляться со всплесками трафика и контролировать затраты
  • Автомасштабирование: Включите автомасштабирование для динамической настройки ёмкости в зависимости от спроса

Рассчитайте требуемую параллельность:

Required Concurrency = Target QPS × Average Latency (seconds)

Например, если ваша цель - 100 QPS со средней задержкой 200 мс:

Required Concurrency = 100 × 0.2 = 20

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

Типы экземпляров

Выберите типы экземпляров на основе требований к вычислительным ресурсам модели:

Тип экземпляра Лучше всего подходит для Trade-offs
ЦП (малый, средний, большой) Упрощенная модель, простая логика вывода Более низкая стоимость, медленнее для моделей с интенсивным вычислением
GPU (малый, средний, большой) Большие модели, сложные вычисления, обработка изображений и видео Более высокая стоимость, оптимальная производительность для глубокого обучения

Подсказка

Начните с экземпляров ЦП для разработки и тестирования. Переключитесь на экземпляры GPU только если наблюдается высокая задержка инференса или если ваша модель требует специализированных вычислений (например, для операций глубокого обучения).

Оптимизации моделей

Оптимизация моделей повышает скорость вывода и эффективность ресурсов.

Размер модели и сложность

Размер и сложность модели: меньшие, менее сложные модели обычно приводят к более быстрому времени вывода и более высокому QPS. Рассмотрите такие методы, как квантизация или обрезка модели, если ваша модель имеет большой размер.

Пакетирование

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

Предварительная обработка и оптимизация после обработки

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

Оптимизации на стороне клиента

Оптимизация на стороне клиента улучшает взаимодействие приложений с конечными точками обслуживания.

Пулинг соединений

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

  • Используйте пакет SDK Databricks, который автоматически реализует рекомендации по пулу подключений
  • При использовании кастомных клиентов реализуйте пул соединений самостоятельно.

Стратегии обработки ошибок и повторных попыток

Реализуйте надежную обработку ошибок для корректной обработки временных сбоев, особенно во время автомасштабирования событий или сбоев в сети.

Оптимизация размера полезной нагрузки

Свести к минимуму размеры полезных данных запросов и ответов, чтобы сократить время передачи данных по сети и повысить пропускную способность.

Измерение и повышение производительности

Отслеживание производительности

Отслеживайте производительность конечной точки с помощью средств, предоставляемых службой модели:

Единица измерения Что он измеряет Цель Действие при превышении
Задержка (P50, P90, P99) Время отклика для запросов Зависимость от приложений (обычно <100–500 мс) Проверка очереди, оптимизации модели или клиента
Пропускная способность (QPS) Количество выполненных запросов в секунду Зависимые от рабочей нагрузки Включение оптимизации маршрута, увеличение выделенной параллельности
Уровень ошибок Процент неудачных запросов <1% Проверка журналов служб, проверка проблем с емкостью
Длина очереди Запросы, ожидающие обработки 0 (без очереди) Увеличение предоставленной параллельности или активация автомасштабирования
Использование ЦП и памяти Загруженность ресурсов <80% Увеличение масштаба типа экземпляра или увеличение параллелизма

См. Мониторинг качества моделей и работоспособности конечных точек для получения детальных указаний и Отслеживание и экспорт метрик работоспособности конечных точек в Prometheus и Datadog для передачи метрик в системы наблюдения.

Нагрузочное тестирование

Нагрузочное тестирование измеряет производительность конечной точки в условиях реального трафика и помогает:

  • Определение наилучших параметров подготовленной параллельности
  • Определите узкие места производительности
  • Проверка требований к задержке и пропускной способности
  • Общие сведения о связи между параллелизмом клиента и параллелизмом сервера

См раздел Нагрузочное тестирование для конечных точек обслуживания.

Устранение распространенных проблем с производительностью

Queuing

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

Очередь возникает, когда скорость запроса или параллелизм превышает текущую емкость обработки конечной точки. Обычно это происходит во время резких пиков трафика, всплесков рабочей нагрузки или при нехватке выделенной одновременности конечного устройства. Конечные серверные точки модели позволяют временному буферу обрабатывать всплески, но по достижении определенного порогового значения HTTP конечная точка возвращает ошибки 429 (слишком много запросов) для защиты стабильности системы.

Очередь увеличивает задержку, так как запросы, находящиеся в очереди, ожидают обработки. Чтобы свести к минимуму очередь, выполните приведенные действия.

  • Установите минимальный выделенный параллелизм на уровне, достаточно высоком, чтобы справляться с базовым трафиком и типичными всплесками.
  • Включение оптимизации маршрута для более высоких ограничений емкости
  • Реализация механизма повторных попыток с экспоненциальной задержкой в клиентских приложениях

Узкие места внешнего API

Модели часто вызывают внешние API для обогащения данных, извлечения признаков или других задач во время вывода. Эти внешние зависимости могут стать узкими местами производительности:

  • Задержка: измеряйте время отклика каждого внешнего вызова API. Высокая задержка в этих вызовах напрямую увеличивает общую задержку обслуживания и уменьшает пропускную способность.
  • Ограничения пропускной способности: внешние API могут накладывать ограничения по скорости или емкости. Превышение этих ограничений может привести к регулированию, ошибкам и снижению производительности.
  • Уровень ошибок: частые ошибки от внешних API могут вызвать повторные попытки и увеличить нагрузку на вашу конечную точку обслуживания.
  • Кэширование: Внедрить кэширование для часто используемых данных с внешних API для сокращения количества вызовов и улучшения времени отклика.

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

Блокирующие вызовы в коде модели на конечных точках CPU

В конечных точках обслуживания пользовательских моделей на CPU, использующих workers gevent, вызов, блокирующийся в скомпилированном коде, может задерживать каждый запрос на этом воркере, даже если вызов выполняется в фоновом потоке. Чтобы избежать этого, запускайте такие вызовы в отдельном пуле потоков ОС.

Воркер gevent может одновременно выполнять несколько запросов. Потоки Python, которые запускает ваш код модели, включая threading.Thread и concurrent.futures.ThreadPoolExecutor, выполняются как кооперативные задачи gevent в рабочем потоке. Они переключаются только при вызовах, которые gevent делает кооперативными, например, при вводе-выводе сокетов, time.sleep, и блокировках, поэтому чистый сетевой ввод-вывод на Python, например с requests, работает как ожидается. Вызов, который ждёт внутри скомпилированного кода, такого как расширение C, C++ или Rust, некоторые драйверы базы данных или SDK, не переключается, поэтому он блокирует весь воркер до возврата. Распространённым симптомом являются скачки задержки или тайм-ауты при многих запросах одновременно, которые совпадают по времени с замедлением нижележащего сервиса.

Чтобы проверить, использует ли ваш эндпоинт gevent workers, запишите в журнал gevent.monkey.is_module_patched("threading") при загрузке модели. На конечных точках, которые не используют gevent, блокирующий вызов задерживает только тот запрос, который его выполнил.

Следующая вспомогательная функция запускает вызов в выделенном пуле потоков ОС при активном gevent и вызывает его напрямую:

_pool = None


def run_blocking(fn, *args, **kwargs):
    """Run fn on an OS thread when gevent is active. Otherwise, call fn directly."""
    try:
        from gevent import monkey
        from gevent.threadpool import ThreadPool
    except ImportError:
        return fn(*args, **kwargs)
    if not monkey.is_module_patched("threading"):
        return fn(*args, **kwargs)
    global _pool
    if _pool is None:
        _pool = ThreadPool(8)
    return _pool.apply(fn, args, kwargs)

Например, в фоновом потоке, который записывает записи с клиентом SDK, ожидающим в скомпилированном коде, вызовите run_blocking(client.write, record) вместо client.write(record). Помните о перечисленных ниже моментах.

  • fn выполняется в другом потоке, чем вызывающий код, и одновременно может выполняться несколько вызовов. Используйте его только с объектами, безопасными для потоков, создавайте объекты, связанные с потоком, такие как подключения к базе данных, внутри fn, и передавайте значения, специфичные для запроса, в качестве аргументов. contextvars и локальные для потока значения, которые задаёт вызывающая сторона, не видны внутри fn. Вызывайте run_blocking из кода Python, который выполняет ваша модель, а не из обратного вызова, который скомпилированная библиотека вызывает в собственном потоке.
  • Установите тайм-аут на самом блокирующем вызове. Поток пула нельзя отменить, поэтому вызов, который никогда не возвращается, сохраняет свой поток. Когда все потоки пула заняты, новые вызовы ждут свободного потока.
  • Разгрузка помогает только если скомпилированный вызов освобождает глобальную блокировку интерпретатора Python (GIL) во время ожидания.
  • Если fn вызывает исключение, run_blocking пробрасывает его в вызывающий код.

Для записи журналов или записей по запросу в таблицу используйте телеметрию конечной точки вместо блокирующего вызова. См. статью "Сохранение пользовательских моделей, обслуживающих данные в каталоге Unity".

Дополнительные ресурсы