• Русский
  • Set Up Autoscaling for Inference Services with KEDA

    Introduction

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

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

    В этом руководстве описывается настройка автоскейлинга KServe с использованием KEDA (Kubernetes Event-driven Autoscaling) и пользовательских метрик, экспортируемых vLLM. Такое сочетание позволяет сервисам вывода масштабироваться на основе реальных сигналов нагрузки, а не общих инфраструктурных метрик.

    INFO

    KEDA расширяет стандартный Kubernetes Horizontal Pod Autoscaler (HPA), позволяя приложениям масштабироваться от нуля до N экземпляров и обратно на основе широкого спектра источников событий — включая метрики Prometheus. Она вводит открытую и расширяемую архитектуру, благодаря чему KServe может масштабироваться практически по любому сигналу, важному для производительности вашей AI-модели.

    Prerequisites

    • Установлен плагин оператора Alauda AI.
    • Установлен плагин оператора KEDA.
    • InferenceService, использующий режим Standard с runtime vLLM.
    • Установлен и доступен в кластере Prometheus.

    Предоставление KServe доступа к ресурсам KEDA

    Перед продолжением примените следующие RBAC-ресурсы, чтобы kserve-controller-manager мог управлять объектами KEDA (ScaledObject, TriggerAuthentication и др.):

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: kserve-keda-manager-role
    rules:
    - apiGroups:
      - keda.sh
      resources:
      - "*"
      verbs:
      - "*"
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: kserve-keda-manager-binding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: kserve-keda-manager-role
    subjects:
    - kind: ServiceAccount
      name: kserve-controller-manager
      namespace: kserve
    [Installation Order]

    Если KEDA была установлена после Alauda AI, перезапустите pod kserve-controller-manager (в namespace kserve) после применения вышеуказанных RBAC, чтобы он обнаружил CRD KEDA:

    kubectl rollout restart deployment kserve-controller-manager -n kserve

    Steps

    Остановите запущенный InferenceService

    Перед внесением изменений остановите запущенный InferenceService, чтобы избежать конфликтов между существующим HPA и новым скейлером, управляемым KEDA. Добавьте следующую аннотацию для остановки:

    kubectl annotate inferenceservice <your-isvc-name> -n <your-namespace> \
      serving.kserve.io/stop='true'
    WARNING

    Если у запущенного InferenceService уже есть ресурс HPA, переключение на KEDA без предварительной остановки вызовет конфликт ресурсов.

    Создайте TriggerAuthentication для Prometheus

    KEDA требует ресурс TriggerAuthentication в том же namespace, что и ваш InferenceService, для аутентификации в Prometheus.

    Учетные данные Prometheus хранятся в секретах платформы kube-prometheus-alertmanager-basic-auth в namespace cpaas-system. Выполните следующую команду, чтобы скопировать их в ваш namespace:

    kubectl create secret generic prom-basic-auth-secret \
      --namespace=<your-namespace> \
      --from-literal=username=$(kubectl get secret kube-prometheus-alertmanager-basic-auth \
        -n cpaas-system -o jsonpath='{.data.username}' | base64 -d) \
      --from-literal=password=$(kubectl get secret kube-prometheus-alertmanager-basic-auth \
        -n cpaas-system -o jsonpath='{.data.password}' | base64 -d)

    Затем создайте TriggerAuthentication, ссылающийся на этот секрет:

    apiVersion: keda.sh/v1alpha1
    kind: TriggerAuthentication
    metadata:
      name: prom-basic-auth
      namespace: <your-namespace>
    spec:
      secretTargetRef:
        - parameter: username
          name: prom-basic-auth-secret
          key: username
        - parameter: password
          name: prom-basic-auth-secret
          key: password
    TIP

    Следующие имена должны быть согласованы во всех ресурсах:

    • prom-basic-auth-secret — имя Secret, должно совпадать с secretTargetRef.name внутри TriggerAuthentication.
    • prom-basic-auth — имя TriggerAuthentication, должно совпадать с authenticationRef.authenticationRef.name в спецификации InferenceService.

    Настройте InferenceService для KEDA

    После остановки сервиса обновите манифест InferenceService, добавив конфигурацию автоскейлинга KEDA:

    apiVersion: serving.kserve.io/v1beta1
    kind: InferenceService
    metadata:
      name: <your-isvc-name>
      namespace: <your-namespace>
      annotations:
        serving.kserve.io/deploymentMode: Standard
        serving.kserve.io/autoscalerClass: keda
    spec:
      predictor:
        maxReplicas: 2
        autoScaling:
          metrics:
            - type: External
              external:
                authenticationRef:
                  authModes: basic
                  authenticationRef:
                    name: prom-basic-auth
                metric:
                  backend: prometheus
                  query: >
                    sum(vllm:num_requests_running{isvc_name="<your-isvc-name>",namespace="<your-namespace>"})
                  serverAddress: http://prometheus-operated.cpaas-system.svc.cluster.local:9090
                target:
                  type: Value
                  value: '1'
        # ... остальная конфигурация predictor
    1. Отключает встроенный HPA KServe и передает масштабирование KEDA.
    2. Устанавливает максимальное количество реплик. Чтобы сервис мог автоматически масштабироваться при увеличении трафика, убедитесь, что значение больше 1 (например, 2).
    3. Ссылается на ресурс TriggerAuthentication, содержащий учетные данные для аутентификации в Prometheus. Замените prom-basic-auth на имя вашего фактического TriggerAuthentication.
    4. Запрос PromQL, возвращающий текущую нагрузку в виде одного числового значения. Замените <your-model-name> и <your-namespace> на ваши реальные значения.
    5. Внутренний адрес вашего экземпляра Prometheus, например, http://prometheus-operated.cpaas-system.svc.cluster.local:9090.
    6. Целевое значение на реплику. KEDA вычисляет ceil(metricValue / value), чтобы определить желаемое количество реплик.

    Метрики vLLM для автоскейлинга

    Метрики vLLM автоматически собираются платформой. Выбор правильной метрики — пожалуй, самая важная часть настройки: запрос Prometheus должен возвращать одно числовое значение, точно отражающее текущую нагрузку на вашу модель.

    Часто используемые метрики vLLM для автоскейлинга:

    МетрикаОписание
    vllm:num_requests_runningКоличество запросов, которые в данный момент обрабатываются моделью
    vllm:num_requests_waitingКоличество запросов в очереди, ожидающих обработки
    vllm:gpu_cache_usage_percПроцент использования GPU KV-кэша
    vllm:e2e_request_latency_seconds_bucketГистограмма задержек полного времени обработки запроса
    vllm:time_per_output_token_seconds_bucketЗадержка между токенами (Time Per Output Token, TPOT)

    Используйте функцию агрегации sum(), чтобы запрос возвращал одно значение по всем pod-ам вашего развертывания. Например, для масштабирования по количеству ожидающих запросов:

    sum(vllm:num_requests_waiting{isvc_name="<your-isvc-name>", namespace="<your-namespace>"})

    Это суммирует все ожидающие запросы по всем pod-ам предиктора, давая KEDA единый агрегированный сигнал для масштабирования.

    Проверьте настройку

    После применения обновленного InferenceService KServe автоматически создаст KEDA ScaledObject от вашего имени. Проверьте, что всё работает:

    # Просмотр созданного KEDA ScaledObject
    kubectl get scaledobject -n <your-namespace>
    
    # Просмотр HPA, управляемого KEDA
    kubectl get hpa -n <your-namespace>
    
    # Наблюдение за количеством реплик в реальном времени
    kubectl get hpa -n <your-namespace> -w

    Вывод HPA покажет текущее значение метрики, порог масштабирования и текущее/желаемое количество реплик. По мере роста трафика на вывод значение TARGETS будет увеличиваться, и количество реплик будет автоматически масштабироваться вверх.