English translation is not available yet. Showing Russian content.

Настроить auto-scaling для vLLM

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить auto-scaling для vLLM

1. Цель задачи

Научиться настраивать горизонтальное масштабирование (horizontal pod autoscaling) инстансов vLLM на основе утилизации GPU. Сконфигурировать механизм, который автоматически добавляет или удаляет реплики vLLM, поддерживая целевой уровень загрузки GPU 70–80% без избыточного выделения ресурсов (overprovisioning).

Ключевой результат Рабочая конфигурация auto-scaling с HPA/KEDA, которая стабилизирует GPU utilization в диапазоне 70–80% под меняющейся нагрузкой, измеряемой синтетическим бенчмарком.


2. Исходные данные

Что нужноОткуда взять
Kubernetes кластер (>=1.24)Minikube / Kind / облачный K8s (EKS, GKE, AKS)
vLLM инстанс, развёрнутый в K8sDocker образ vllm/vllm-openai:latest или собранный
Метрики GPU (utilization, memory)NVIDIA DCGM Exporter, Prometheus
Prometheus + kube-state-metricsHelm-чарты, установленные в кластере
HPA (Horizontal Pod Autoscaler) или KEDAВстроенный в K8s или KEDA operator

Если нет реального инструмента — симулируем:

  1. Развернуть локальный K8s кластер через Kind (1 control-plane, 2 worker nodes).
  2. Установить NVIDIA GPU Operator (если есть GPU) или использовать nvidia/dcgm-exporter без GPU для симуляции — в этом случае использовать custom metric на основе CPU utilisation, эмулируя GPU workload.
  3. Установить Prometheus stack через Helm (prometheus-community/kube-prometheus-stack).
  4. Написать простой Python-скрипт генератора нагрузки (отправка запросов к vLLM через OpenAI API).

3. Технологический стек

КомпонентИнструментыНазначение
КонтейнеризацияDocker, Kubernetes (Kind)Запуск vLLM
GPU метрикиNVIDIA DCGM Exporter, PrometheusСбор utilization
Auto-scalingHPA (Kubernetes) / KEDAГоризонтальное масштабирование
Нагрузочное тестированиеPython + requests / locustГенерация синтетического трафика
МониторингGrafanaДашборд GPU utilization
КонфигурацияHelm, YAML манифестыРазвёртывание компонентов

4. Этапы выполнения

Этап 1: Развёртывание vLLM и сбор метрик GPU (1.5 часа)

Действия

  1. Создать namespace vllm-system в K8s.
  2. Развернуть NVIDIA DCGM Exporter через Helm:
    helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
    helm upgrade --install dcgm-exporter nvidia/dcgm-exporter \
      --namespace vllm-system \
      --set serviceMonitor.enabled=true
    
  3. Убедиться, что метрики поступают в Prometheus: DCGM_FI_DEV_GPU_UTIL.
  4. Развернуть vLLM с помощью Deployment и Service (пример deployment.yaml):
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: vllm-server
      namespace: vllm-system
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: vllm-server
      template:
        metadata:
          labels:
            app: vllm-server
        spec:
          containers:
          - name: vllm
            image: vllm/vllm-openai:latest
            args: ["--model", "mistralai/Mistral-7B-Instruct-v0.2", "--port", "8000", "--tensor-parallel-size", "1"]
            ports:
            - containerPort: 8000
            resources:
              limits:
                nvidia.com/gpu: 1
            env:
            - name: HUGGINGFACE_HUB_CACHE
              value: "/data"
    
  5. Установить ServiceMonitor для vLLM (если vLLM экспортирует prometheus метрики) или использовать kube-state-metrics для подов.

Ожидаемый результат этапа vLLM работает, метрики GPU utilization отображаются в Prometheus.


Этап 2: Создание HPA на основе GPU utilization (1 час)

Действия

  1. Настроить Prometheus Adapter для экспорта метрики DCGM_FI_DEV_GPU_UTIL как кастомной метрики в API metrics.
    # values-prom-adapter.yaml
    rules:
      default: true
      custom:
      - seriesQuery: 'DCGM_FI_DEV_GPU_UTIL{namespace="vllm-system"}'
        resources:
          overrides:
            namespace: {resource: "namespace"}
            pod: {resource: "pod"}
        name:
          as: "gpu_utilization"
        metricsQuery: avg(<<.Series>>{<<.LabelMatchers>>}) by (pod)
    
  2. Установить Prometheus Adapter: helm install prometheus-adapter prometheus-community/prometheus-adapter -f values-prom-adapter.yaml.
  3. Создать HPA ресурс:
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: vllm-hpa
      namespace: vllm-system
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: vllm-server
      minReplicas: 1
      maxReplicas: 5
      metrics:
      - type: Pods
        pods:
          metric:
            name: gpu_utilization
          target:
            type: AverageValue
            averageValue: 75  # 75% utilization target
    
  4. Проверить, что HPA видит метрику: kubectl get hpa -n vllm-system.

Ожидаемый результат этапа HPA создан, target metric показывает актуальное значение GPU utilization.


Этап 3: Нагрузочное тестирование и проверка масштабирования (1 час)

Действия

  1. Написать скрипт генерации нагрузки load_gen.py:
    import requests
    import concurrent.futures
    import time
    
    url = "http://<vllm-service>:8000/v1/chat/completions"
    payload = {
        "model": "mistralai/Mistral-7B-Instruct-v0.2",
        "messages": [{"role": "user", "content": "Расскажи подробно про машинное обучение."}],
        "max_tokens": 512
    }
    
    def send_request():
        requests.post(url, json=payload, timeout=30)
    
    # Параллельные запросы
    while True:
        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
            futures = [executor.submit(send_request) for _ in range(20)]
            concurrent.futures.wait(futures)
        time.sleep(2)
    
  2. Запустить скрипт, постепенно увеличивая количество параллельных запросов (например, 5 → 10 → 20 → 50).
  3. Наблюдать в Grafana (или через kubectl top pods) изменение GPU utilization.
  4. Когда utilization превысит 80%, HPA должен начать масштабирование. Зафиксировать количество реплик до и после.

Ожидаемый результат этапа При нагрузке количество реплик увеличивается до стабилизации utilization ~75%; при спаде нагрузки реплики уменьшаются до minReplicas.


Этап 4: Тюнинг параметров и оптимизация (1 час)

Действия

  1. Настроить cool down и stabilization window в HPA:
    behavior:
      scaleDown:
        stabilizationWindowSeconds: 60
        policies:
        - type: Pods
          value: 1
          periodSeconds: 60
      scaleUp:
        stabilizationWindowSeconds: 30
    
  2. Протестировать сценарий резкого скачка нагрузки (flash crowd) — HPA не должен thrash.
  3. Оптимизировать target averageValue: если utilisation колеблется, попробовать 70% для более агрессивного масштабирования.
  4. Включить resource metrics (CPU, memory) как дополнительную метрику для HPA, чтобы избежать масштабирования под 0 при отсутствии GPU нагрузки.
  5. Установить KEDA ScaledObject как альтернативу, если требуется более тонкая настройка.

Ожидаемый результат этапа HPA стабильно поддерживает utilization 70-80% без лишних реплик и без частых масштабирований.


Этап 5: Документирование и дашборд (30 минут)

Действия

  1. Создать Grafana dashboard с панелями:
    • GPU utilization (avg по подам)
    • Количество реплик vLLM
    • Request latency (p50, p95)
    • Частота scale-up/down событий
  2. Написать README с инструкцией по развёртыванию автоскейлинга.
  3. Зафиксировать конфигурационные файлы (deployment.yaml, hpa.yaml, values-prom-adapter.yaml) в Git.

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


5. Критерии приемки (Definition of Done)

  • HPA успешно создан и видит custom metric gpu_utilization для всех подов.
  • При синтетической нагрузке 50 параллельных запросов количество реплик увеличивается с 1 до 3-5 в течение 3 минут.
  • Утилизация GPU стабилизируется в диапазоне 70–80% (±5%) в течение периода нагрузки.
  • После прекращения нагрузки количество реплик возвращается к minReplicas за время не более 3 минуты.
  • Ни один инстанс не достигает 100% GPU utilization дольше 30 секунд.
  • Дашборд Grafana отображает ключевые метрики автоскейлинга.
  • Все конфигурационные файлы сохранены в репозитории.
  • Выполнен сценарий thrash-теста: резкое повышение нагрузки не вызывает циклического масштабирования (scale-up/down чаще раза в минуту).

6. Ожидаемый результат

Основной артефакт Набор YAML-манифестов:

  • deployment.yaml — Deployment vLLM с resource limits
  • hpa.yaml — HPA с кастомной метрикой
  • values-prom-adapter.yaml — конфигурация Prometheus Adapter
  • values-dcgm-exporter.yaml — настройки DCGM Exporter
  • load_gen.py — скрипт для генерации нагрузки
  • README.md — описание и команды развёртывания

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

  • Grafana dashboard JSON (экспортированный).
  • Отчёт о тестировании: графики utilization, количество реплик, задержки.

7. Возможные сложности и их решение

СложностьРешение
GPU метрика не появляется в PrometheusПроверить serviceMonitor у DCGM Exporter, label selector у Prometheus, namespace
HPA не видит кастомную метрикуУбедиться, что Prometheus Adapter настроен правильно и метрика доступна по адресу /apis/custom.metrics.k8s.io/v1beta1
Масштабирование слишком медленноеУменьшить stabilizationWindowSeconds для scaleUp, увеличить агрегацию метрики
Частое масштабирование (thrashing)Установить поведение scaleDown с задержкой и полиси, использовать несколько метрик (CPU + GPU)
vLLM не успевает загрузить модель на новой репликеИспользовать ReadinessProbe с проверкой /health, предварительно скачать модель в PVC или образе
Нет физического GPUИспользовать CPU-only vLLM или эмуляцию через DCGM Exporter на CPU (метрика = CPU utilization)

8. Бюджет времени (оценка)

ЭтапВремя
Этап 1: Развёртывание vLLM и сбор метрик GPU1.5 ч
Этап 2: Создание HPA на основе GPU utilization1 ч
Этап 3: Нагрузочное тестирование1 ч
Этап 4: Тюнинг и оптимизация1 ч
Этап 5: Документирование и дашборд0.5 ч
Итого5 ч

Примечание Для первого выполнения рекомендуется заложить +2 ч на отладку Kubernetes/Prometheus. Если нет GPU, время увеличится на 1 ч за счёт симуляции.


9. Связанные вопросы из базы знаний

ВопросТема
55Как настроить Prometheus Adapter для кастомных метрик?
112Параметры HPA: stabilizationWindow и поведение при scale up
203Мониторинг GPU utilization в Kubernetes через DCGM Exporter
401vLLM: оптимальная конфигурация tensor-parallel-size для масштабирования
567Экономика auto-scaling: расчёт стоимости при переключении реплик
688KEDA ScaledObject vs HPA: когда что использовать
789Оптимизация холодного старта vLLM в auto-scaling
832GPU фрагментация памяти: влияние на масштабирование
899Best practices: target utilization для GPU в inference
900Тестирование auto-scaling с Locust и синтетическими данными

10. Чек-лист самопроверки

  • Я убедился, что метрика GPU utilization корректно агрегируется по поду (avg по всем GPU в поде).
  • Я проверил, что HPA использует averageValue, а не averageUtilization, так как последний не поддерживается для custom metrics.
  • Я протестировал сценарий с низкой нагрузкой — реплика не уменьшается ниже 1.
  • Я настроил behavior чтобы избежать oscillation.
  • Я сохранил все конфигурационные файлы и скрипты в репозиторий.
  • Я выгрузил дашборд Grafana и приложил к результатам.
  • Я выполнил тест на thrashing: резкий скачок нагрузки не вызывает частых scale-up/down.