English translation is not available yet. Showing Russian content.
Настроить autoscaling для LLM сервера
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить autoscaling для LLM сервера
1. Цель задачи
Научиться проектировать и внедрять автоматическое масштабирование (автоскейлинг) для сервера инференса большой языковой модели (LLM) на основе реальной нагрузки. Основная метрика для масштабирования — загрузка GPU (GPU utilization) и длина очереди запросов (queue length). Цель — обеспечить такое количество реплик сервера, которое минимизирует задержки при пиковой нагрузке и не создаёт избыточных затрат (оверпровижен) в периоды простоя.
Ключевой результат Настроенный и протестированный HPA (Horizontal Pod Autoscaler) в Kubernetes, который автоматически увеличивает/уменьшает количество подов LLM-сервера в зависимости от текущей загрузки GPU и глубины очереди, без ручного вмешательства и с экономией ресурсов.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Kubernetes-кластер (minikube, kind, managed K8s) | Локальный или облачный (например, GKE, EKS, AKS) |
| LLM-сервер в контейнере (vLLM, TGI, или собственный FastAPI) | Docker image, готовый к деплою |
| GPU-ускоритель (NVIDIA) | Node с GPU в кластере (минимум 1 GPU) |
| Prometheus для сбора метрик | Установить через Helm или оператор |
| Grafana для визуализации | Установить через Helm |
| NVIDIA DCGM Exporter для метрик GPU | Helm-чарт или DaemonSet |
| KEDA или custom-metrics-apiserver для работы с очередью | Установить через Helm |
| Инструмент для генерации нагрузки (locust, hey, k6) | pip install или бинарник |
Если нет реального GPU-кластера — симулируем:
- Использовать инстанс с GPU в облаке (например, 1x T4 в GCP/GKE, или AWS g4dn.xlarge) или локальный компьютер с NVIDIA GPU.
- Если GPU нет — развернуть CPU-only LLM-сервер (малую модель, например, distilgpt2) и настроить HPA по queue length как основной метрике; GPU utilization в этом случае эмулировать не нужно, но в задании требуется именно GPU utilization — поэтому без GPU не обойтись. Рекомендуется взять облачный GPU за $0.5-1/час.
- Для очереди: LLM-сервер должен иметь endpoint
/generateс внутренней очередью (например, vLLM уже имеет очередь запросов). Если нет — добавить Redis-очередь через sidecar контейнер.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Оркестрация | Kubernetes (minikube / kind / managed) | Деплой и управление подами |
| LLM сервер | vLLM / HuggingFace TGI / FastAPI + transformers | Инференс LLM |
| Мониторинг | Prometheus + Grafana | Сбор и визуализация метрик |
| Метрики GPU | NVIDIA DCGM Exporter | GPU utilization, memory, temperature |
| Custom Metrics API | Prometheus Adapter / KEDA | Преобразует Prometheus метрики в HPA |
| Автоскейлинг | Kubernetes HPA (горизонтальный) | Автоматическое изменение числа подов |
| Генерация нагрузки | Locust / hey / k6 | Создание запросов к LLM-серверу |
| Инфраструктура as Code | Helm / YAML манифесты | Воспроизводимость конфигурации |
4. Этапы выполнения
Этап 1: Развёртывание LLM-сервера и базового мониторинга (2–3 часа)
Действия
- Установить Kubernetes (например, minikube --driver=nvidia или kind с GPU поддержкой).
- Установить NVIDIA GPU Operator через Helm:
helm repo add nvidia https://nvidia.github.io/gpu-operator helm install gpu-operator nvidia/gpu-operator --create-namespace --namespace nvidia-gpu-operator - Развернуть LLM-сервер (vLLM) через Deployment. Пример конфигурации:
apiVersion: apps/v1 kind: Deployment metadata: name: llm-server spec: replicas: 1 selector: matchLabels: app: llm-server template: metadata: labels: app: llm-server spec: containers: - name: llm image: vllm/vllm-openai:latest args: ["--model", "mistralai/Mistral-7B-v0.1", "--port", "8000"] resources: limits: nvidia.com/gpu: 1 ports: - containerPort: 8000 - Установить Prometheus и Grafana через Helm (kube-prometheus-stack).
- Установить NVIDIA DCGM Exporter:
helm install dcgm-exporter nvidia/dcgm-exporter --namespace monitoring - Проверить, что метрики GPU (
DCGM_FI_DEV_GPU_UTIL,DCGM_FI_DEV_MEM_COPY_UTIL) появляются в Prometheus. - Развернуть Service для LLM-сервера и Ingress (опционально).
Ожидаемый результат этапа Работающий LLM-сервер в кластере, доступный по эндпоинту, и Prometheus собирает метрики GPU utilization.
Этап 2: Настройка метрики queue length (1–2 часа)
Действия
- Если LLM-сервер не экспортирует длину очереди, добавить sidecar-контейнер с Prometheus exporter, который мониторит очередь. Проще всего — использовать KEDA с Prometheus скалером, который может определять очередь из внешних источников (например, RabbitMQ, Redis).
В задании предполагаем, что queue length — это количество ожидающих запросов в эндпоинте LLM. vLLM предоставляет метрикуvllm:num_requests_waitingв/metrics. - Включить эндпоинт
/metricsу vLLM (по умолчанию включён на порту 8000). - Проверить наличие метрики
vllm:num_requests_waitingв Prometheus. - (Альтернатива) Если нет встроенной очереди, развернуть Redis Queue (RQ) и создать консьюмер, который забирает задачи для LLM. Redis exporter предоставит метрику длины очереди.
Ожидаемый результат этапа Prometheus содержит метрику llm_queue_length (или аналогичную), которая изменяется при отправке запросов.
Этап 3: Настройка Prometheus Adapter и HPA (2–3 часа)
Действия
- Установить Prometheus Adapter для преобразования Prometheus метрик в Custom Metrics API:
helm install prometheus-adapter prometheus-community/prometheus-adapter \ --set prometheus.url=http://prometheus-operated.monitoring.svc:9090 - Настроить конфигурацию адаптера (
values.yaml) для двух метрик:gpu_utilization(average за 1 минуту по всем GPU)queue_length(average за 1 минуту) Пример rules:
rules: - seriesQuery: 'DCGM_FI_DEV_GPU_UTIL{gpu=""}' resources: template: ".*" name: matches: "DCGM_FI_DEV_GPU_UTIL" as: "gpu_utilization" metricsQuery: "avg(<<.Series>>) by (<<.GroupBy>>)" - seriesQuery: 'vllm:num_requests_waiting' resources: template: ".*" name: as: "queue_length" metricsQuery: "sum(<<.Series>>)" - Проверить, что Custom Metrics API доступен:
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 - Создать HPA, который использует обе метрики:
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: llm-server-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: llm-server minReplicas: 1 maxReplicas: 4 metrics: - type: Object metric: name: gpu_utilization target: type: AverageValue averageValue: 70 # scale up if avg GPU util > 70% - type: Object metric: name: queue_length target: type: AverageValue averageValue: 5 # scale up if avg queue > 5 requests - (Важно) Настроить
behaviorв HPA, чтобы избежать тревоги при кратковременных скачках:behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 60 policies: - type: Percent value: 100 periodSeconds: 60
Ожидаемый результат этапа HPA создан и отображается в kubectl get hpa. При отсутствии нагрузки replica count = 1.
Этап 4: Генерация нагрузки и проверка автоскейлинга (2–3 часа)
Действия
- Развернуть инструмент генерации нагрузки, например Locust:
(locustfile.py должен слать запросы с постепенным увеличением числа пользователей)apiVersion: v1 kind: Pod metadata: name: load-generator spec: containers: - name: locust image: locustio/locust command: ["locust", "-f", "/scripts/locustfile.py", "--host", "http://llm-server:8000"] volumeMounts: - mountPath: /scripts name: scripts volumes: - name: scripts configMap: name: locust-config - Запустить нагрузку с шаблоном:
- 0–10 мин: низкая нагрузка (1–2 concurrent users)
- 10–20 мин: средняя нагрузка (10–15 users)
- 20–30 мин: пиковая нагрузка (30–40 users)
- 30–40 мин: спад до 0.
- Наблюдать в Grafana дашборд: GPU utilization, queue length, replica count.
- Убедиться, что HPA увеличивает реплики в течение 2-3 минут после превышения порогов, и снижает после стабилизации.
- Проверить overseas (overprovision): после спада нагрузки количество реплик должно вернуться к 1 в течение 5–10 минут (с учетом stabilizationWindow).
- Замерить время реакции HPA и среднюю задержку LLM-сервера во время пика (должна оставаться приемлемой, <10с).
Ожидаемый результат этапа Графики в Grafana показывают, что реплики растут только при высокой нагрузке и снижаются при её отсутствии. Нет лишних запущенных подов (overprovision).
Этап 5: Оптимизация и документирование (1–2 часа)
Действия
- Подобрать оптимальные пороговые значения (target average value) для GPU util и queue length, чтобы минимизировать время реакции и избежать частых скейлов (thrashing).
- Настроить HPA на использование
averageUtilizationвместоaverageValueдля GPU (если есть суммарная ёмкость):(требует установки метрики- type: Resource resource: name: nvidia.com/gpu target: type: Utilization averageUtilization: 70nvidia.com/gpuчерез DCGM) - Задокументировать все шаги и конфиги в README репозитория.
- Написать Postmortem-подобный отчёт: какие параметры выбраны, почему, результаты тестов.
Ожидаемый результат этапа Финальная конфигурация HPA, дашборд Grafana с ключевыми метриками и документированный процесс.
5. Критерии приемки (Definition of Done)
- LLM-сервер развёрнут в Kubernetes, доступен по Service.
- Prometheus собирает метрики GPU utilization (DCGM_FI_DEV_GPU_UTIL) и queue length (vllm:num_requests_waiting).
- Prometheus Adapter корректно преобразует обе метрики в Custom Metrics API.
- HPA создан с minReplicas=1 и maxReplicas≥3, использует обе метрики.
- При низкой нагрузке (0–5 concurrent users) количество реплик остаётся 1.
- При высокой нагрузке (30+ concurrent users) количество реплик возрастает до maxReplicas.
- После снижения нагрузки количество реплик возвращается к 1 не дольше чем через 7 минут.
- В дашборде Grafana отображаются графики replica count, GPU utilization, queue length.
- Не наблюдается оверпровижен: среднее количество реплик за период простоя ≤1.2.
- Документация включает объяснение выбора порогов и анализ результатов теста.
6. Ожидаемый результат
Основной артефакт Архив или репозиторий, содержащий:
hpa.yaml— манифест HPA с настройками.prometheus-adapter-values.yaml— конфигурация адаптера.deployment-llm.yaml— манифест развёртывания LLM-сервера.locustfile.py— скрипт для генерации нагрузки.README.md— инструкция по развёртыванию, описание архитектуры и анализ результатов.
Дополнительно
- Скриншоты Grafana с графиками нагрузки и реплик.
- Лог выполнения теста (например, вывод
kubectl get hpa -w). - Краткий отчёт (1-2 стр.) с выводами и предложениями по улучшению.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| GPU недоступен в локальном кластере | Использовать облачный инстанс с GPU или эмулировать через device plugin (но не даст реальной нагрузки). Лучше взять managed K8s с GPU node pool. |
| Метрика queue_length не появляется в Prometheus | Проверить, что LLM-сервер экспортирует /metrics и что ServiceMonitor настроен (или конфигурация scrape). Использовать kubectl port-forward на /metrics. |
| HPA не видит custom metrics | Проверить, что Prometheus Adapter зарегистрирован в Custom Metrics API (kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1). Проверить правильность метрик в rules. |
| Частые колебания реплик (thrashing) | Увеличить stabilizationWindowSeconds для scaleDown, уменьшить scaleUp policies. Использовать averageUtilization вместо averageValue для GPU. |
| При пиковой нагрузке очередь растёт, но GPU utilisation низкий (например, из-за I/O) | Скорректировать target по queue length, добавить метрику CPU или latency. Рассмотреть VPA для CPU. |
| Ограничение maxReplicas не хватает для пиковой нагрузки | Увеличить maxReplicas или использовать cluster autoscaler для добавления новых нод. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Развёртывание LLM-сервера и мониторинга | 2–3 ч |
| Этап 2: Настройка метрики queue length | 1–2 ч |
| Этап 3: Настройка Prometheus Adapter и HPA | 2–3 ч |
| Этап 4: Генерация нагрузки и проверка | 2–3 ч |
| Этап 5: Оптимизация и документирование | 1–2 ч |
| Итого | 10–12 ч |
Примечание: Если выполняется впервые с нуля и незнакомы инструменты, время увеличится до 20 ч. Рекомендуется разбить на 2–3 дня.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Как установить и настроить Prometheus в Kubernetes |
| 34 | Как развернуть vLLM в кластере |
| 45 | Основы метрик GPU и DCGM |
| 78 | Создание Custom Metrics API с Prometheus Adapter |
| 112 | Настройка HPA с несколькими метриками |
| 156 | Поведенческие настройки HPA (stabilization window) |
| 189 | Установка KEDA для event-driven autoscaling |
| 223 | Избегание оверпровижена в автоскейлинге |
| 287 | Генерация нагрузки с помощью Locust |
| 340 | Бюджет времени и стоимость GPU инстансов |
10. Чек-лист самопроверки
- Я развернул LLM-сервер и убедился, что он отвечает на запросы.
- Я настроил сбор метрик GPU utilization и queue length в Prometheus.
- Я настроил Custom Metrics API и проверил, что
kubectl get hpaпоказывает целевую метрику. - Я запустил генерацию нагрузки с разными уровнями и зафиксировал изменения реплик.
- Я убедился, что после спада нагрузки реплики уменьшились до 1 и не происходит постоянного масштабирования вхолостую.