Как вы разворачиваете LLM в production (self-hosted)?

Краткий тезис

Самый распространённый и надёжный способ self-hosted production для LLM — использование специализированных инференс-серверов, таких как vLLM, TGI (Text Generation Inference) или TensorRT-LLM. Ключевые элементы: квантование модели для снижения требований к памяти, scaling|горизонтальное масштабирование через балансировщик нагрузки, правильный подбор GPU (A100/H100 для больших моделей, L4/A10G для небольших) и мониторинг latency/throughput. vLLM стал стандартом благодаря встроенному Attention|paged attention, continuous batching и поддержке KV-cache.


1. Термин: Self-hosted production

Self-hosted production — это развёртывание LLM на собственной инфраструктуре (on-premises или в приватном облаке), в отличие от использования облачных API (OpenAI, Anthropic). Необходимо обеспечить низкую задержку, высокую пропускную способность, отказоустойчивость и безопасность.

Почему выбирают self-hosted

  • Контроль над данными (data residency, compliance, GDPR, HIPAA)
  • Предсказуемая стоимость при высоких нагрузках (нет платы за токен)
  • Возможность кастомизации (fine‑tuning, специфичные конфигурации)
  • Низкая задержка (инфраструктура рядом)

Вызовы

  • Управление GPU и их высокая стоимость
  • Сложность масштабирования и мониторинга
  • Необходимость в MLOps‑инженерах

2. Инференс-серверы: сравнение и выбор

Инференс-сервер — это программа, которая принимает запросы, запускает модель и возвращает результат, оптимизируя использование GPU. Основные кандидаты:

СерверКомпанияОсобенностиПлюсыМинусы
vLLMСообщество (UC Berkeley)Paged attention, continuous batching, prefix caching, поддержка большинства моделейЛучшая производительность для большинства сценариев, простая конфигурация, открытый кодНет встроенной поддержки Triton Inference Server (но можно обернуть)
TGI (Text Generation Inference)Hugging FaceSafeTensors, flash attention, интеграция с HF ecosystemПростота развёртывания, встроенная поддержка quantisation (bitsandbytes, GPTQ)Меньше гибкости в управлении памятью, чем vLLM
TensorRT-LLMNVIDIATensorRT оптимизации, поддержка многопоточности, in-flight batchingМаксимальная производительность на NVIDIA GPU (до 4x ускорение)Сложность компиляции, привязка к hardware, требуется NVIDIA GPU
DeepSpeed (DeepSpeed-MII / Inference)MicrosoftZero-оптимизация, инференс через MIIХорош для very large models (ZeROInference)Меньше community adoption, чем vLLM

Рекомендация для 90% проектов — vLLM. Он прост в настройке, поддерживает гибридное квантование, легко интегрируется с Kubernetes и даёт отличный throughput.

Ключевой механизм: Paged attention

  • Разделяет KV-cache на блоки, аналогично виртуальной памяти в ОС
  • Позволяет эффективно использовать видеопамять, избегая её фрагментации
  • Увеличивает throughput в 2–4x по сравнению с vanilla transformers

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


3. Оборудование: выбор GPU и RAM

Выбор GPU зависит от размера модели, требуемой latency и бюджета.

МодельРазмерРекомендованная GPUVRAM (min)VRAM (комфортно)Пример throughput (vLLM)
Llama‑3‑8B8BL4 (24GB), A10G (24GB)16GB24GB50–100 req/s (batch=16)
Llama‑3‑70B70BA100‑80GB, H100‑80GB140GB (квантование 4‑bit: 35GB)80GB (FP16)10–20 req/s (batch=8)
Mixtral 8x7B~47BA100‑80GB, H10090GB (FP16) или 48GB (4‑bit)80GB20–30 req/s
GPT‑J‑6B6BT4 (16GB), L412GB16GB100–150 req/s

Важно учитывайте не только модель, но и KV-cache — для контекстной длины 8K и batch=16 он может потребовать дополнительно 2–8GB.

CPU RAM — обычно 32–64GB для ОС и обработки данных, но для больших моделей может потребоваться больше (особенно при загрузке через CPUoffload).


4. Квантование (Quantisation)

Квантование — снижение точности весов модели (например, с FP16 до INT4), что уменьшает потребление памяти и ускоряет инференс на современных GPU (поддержка тензорных ядер INT4/INT8).

ТипБитностьЭффект на качествоСкорость (vs FP16)Примечание
FP1616Эталон1xТребует много VRAM
INT88Минимальная потеря~1.5–2xХорош для большинства задач
INT4 (GPTQ/AWQ)4Небольшая потеря (1–2% perplexity)~2–3xСтандарт для 70B+ моделей
NF4 (bitsandbytes)4Чуть больше потерь~2xУдобен для быстрых экспериментов

Популярные методы квантования

  • GPTQ: точное пост-обучение, требует калибровочного датасета, высокая точность.
  • AWQ (Activation-aware Weight Quantization): учитывает распределение активаций, часто даёт лучшее качество, чем GPTQ.
  • bitsandbytes (from Hugging Face): быстрое квантование на лету, но медленнее на инференсе.

На практике для Llama‑3‑70B используйте AWQ 4‑bit — помещается на одной A100‑80GB. Для Llama‑3‑8B можно обойтись FP16 на A10G.


5. Масштабирование (Scaling)

Горизонтальное масштабирование — добавление нескольких реплик сервера за балансировщиком нагрузки (например, Nginx, HAProxy, AWS ALB или Envoy).

Архитектура

Client → Load Balancer → [vLLM instance 1, vLLM instance 2, ...]
  • Каждый инстанс использует одну GPU (или несколько в случае tensor parallelism).
  • Балансировщик распределяет запросы по round‑robin или по количеству свободных слотов (vLLM сообщает о занятости через health‑check).

Tensor parallelism — разделение модели на несколько GPU (например, 2x A100 для Llama‑70B). Поддерживается vLLM через --tensor-parallel-size 2.

Pipeline parallelism — реже, так как вводит задержку (pipeline bubbles).

Auto‑scaling — при использовании Kubernetes (K8s) с HorizontalPodAutoscaler на основе метрик (GPU utilization, latency p99, количество запросов в очереди). Обычно используют Kubernetes Event‑driven Autoscaling (KEDA) с очередями (Redis/RabbitMQ).

Что масштабировать

  • Количество реплик (экземпляров процесса)
  • Количество тензорных пар (при tensor parallelism)

Важно при добавлении реплик увеличивается throughput, но не уменьшается latency (каждый запрос по-прежнему обрабатывается одной моделью).


6. Кэширование и оптимизация инференса

KV‑cache — сохраняет ключи и значения attention для уже сгенерированных токенов. В vLLM он реализован как paged attention (блочная память), что минимизирует фрагментацию.

Prefix caching — если у многих запросов одинаковый префикс (например, системный промпт «You are a helpful assistant...»), vLLM может кэшировать его KV‑cache и повторно использовать для новых запросов. Это ускоряет prefill‑фазу.

Speculative decoding — использует маленькую модель (drafter) для генерации нескольких токенов, а большая модель (target) их верифицирует. vLLM поддерживает это экспериментально. Ускоряет до 2–3x при batch=1.

Attention kernel оптимизации

  • FlashAttention — ускоряет вычисление attention, уменьшает использование GPU‑памяти.
  • PagedAttention (собственный) — эффективное управление KV‑cache.

Continuous batching — ключевая оптимизация vLLM, которая позволяет комбинировать запросы на разных стадиях генерации в один большой батч на GPU. Без неё throughput падал бы в 2–3 раза.


7. Развёртывание: Docker / Kubernetes / Triton

Docker — упаковка сервера (например, vllm/vllm‑openai:latest) с монтированием модели (из Hugging Face или локально).

Пример Dockerfile:

FROM vllm/vllm-openai:latest
# модель можно скачать при запуске или смонтировать volume
EXPOSE 8000
CMD ["--model", "meta-llama/Meta-Llama-3-8B-Instruct", "--quantization", "awq", "--dtype", "auto"]

Kubernetes

  • Deployment с репликами (replicas)
  • Service типа ClusterIP или LoadBalancer
  • Ingress для внешнего трафика
  • PersistentVolume для кэша моделей (Hugging Face cache, локальные веса)
  • Pod Autoscaler по GPU Util (через DCGM Exporter и Prometheus)

Triton Inference Server (NVIDIA) — может служить шлюзом, агрегируя несколько моделей, поддерживает dynamic batching и model ensembles. vLLM можно обернуть как backend для Triton (есть интеграция).

Health‑checks

  • Liveness probe: /health
  • Readiness probe: проверка, что модель загружена и готова принимать запросы (можно кастомный эндпоинт /v1/models).

Безопасность

  • Аутентификация через API‑ключи (переменные среды)
  • Ограничение по IP (NetworkPolicy)
  • Шифрование трафика (TLS)
  • Защита от запросов большого размера (max input tokens)

8. Мониторинг и observability

МетрикаОписаниеИнструмент
Latency (p50, p95, p99)Время от запроса до ответаPrometheus + Grafana + vLLM metrics (vllm:request:latency_seconds)
ThroughputЗапросов в секунду или токенов в секундуvLLM vllm:request:throughput
GPU utilisationПроцент занятости GPUDCGM Exporter (NVIDIA), nvidia‑smi
VRAM usageИспользование памятиDCGM metrics
Queue sizeКоличество ожидающих запросовvLLM vllm:request:waiting_requests
Number of active requestsТекущие батчиvLLM

Логирование: структурированные логи (JSON) через ELK или Loki. Собирайте ошибки (например, 400 Bad Request, 503 Service Unavailable).

Alerting если p99 latency > 2s (зависит от SLA) или GPU util > 95% — предупреждения.


9. Пример конфигурации: Llama‑3‑8B на 1× A10G через vLLM

Цель 50–100 запросов/сек, p99 latency < 500ms.

Оборудование

  • GPU: A10G (24GB VRAM)
  • RAM: 32GB, 4 CPU
  • Storage: 20GB для модели (веса ~16GB в FP16)

Команда запуска

docker run --gpus all -p 8000:8000 \
  vllm/vllm-openai:latest \
  --model meta-llama/Meta-Llama-3-8B-Instruct \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.90 \
  --tensor-parallel-size 1 \
  --enable-prefix-caching

Настройки

  • gpu-memory-utilization 0.90 — оставляет 10% для аллокации других процессов
  • enable-prefix-caching — ускоряет обработку повторяющихся префиксов
  • max-model-len 8192 — баланс между контекстом и памятью (можно увеличить до 16384, но throughput упадёт)

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

# Используем openai.py клиент
import openai, time, asyncio

client = openai.AsyncOpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
async def send():
    start = time.time()
    response = await client.completions.create(
        model="meta-llama/Meta-Llama-3-8B-Instruct",
        prompt="Hello, how are you?",
        max_tokens=100)
    return time.time() - start

latencies = await asyncio.gather(*[send() for _ in range(100)])
print(f"p50: {sorted(latencies)[50]:.3f}s, p99: {sorted(latencies)[99]:.3f}s")

Результат ~80 req/s, p50 200ms, p99 400ms при batch=16 (continuous batching).


10. Проблемы и best practices

ПроблемаРешение
Cold start (модель долго загружается)Предварительно скачать веса, использовать --download-dir, предзагрузка модели при старте Pod (init container)
Memory fragmentationPaged attention (vLLM) решает; также можно перезапускать инстанс каждые несколько часов
OOM (out‑of‑memory)Уменьшить gpu-memory-utilization, снизить max-model-len, использовать квантование
High latency при малом batchУвеличить batch до 8–32 (continuous batching), включить flash-attention
ТокенизацияИспользовать тот же токенизатор, что и при обучении; проверять padding side
SecurityОграничить максимальную длину input (через max-model-len), валидировать входные данные
Rolling updatesВ Kubernetes использовать RollingUpdate с maxSurge=25%

Best practice

  • Используйте canary‑развёртывание (новую версию модели на 10% трафика).
  • Внедрите A/B‑тестирование с помощью балансировщика (разные экземпляры с разными моделями/квантованием).
  • Мониторьте не только latency, но и perplexity ответов (качество не должно ухудшаться).

Пет-проект для закрепления

Задача Развернуть self‑hosted инференс Llama‑3‑8B с vLLM на одной машине с GPU (можно использовать облачный инстанс, например EC2 G5.xlarge с A10G) и обеспечить через балансировщик два экземпляра.

Инструменты

  • Docker, docker-compose
  • vLLM (docker‑образ)
  • Nginx как reverse proxy (балансировщик)
  • Python + asyncio для нагрузочного теста

Шаги:

  1. Запустите два контейнера vLLM на разных портах (8001, 8002) с одной моделью.
  2. Сконфигурируйте Nginx (или HAProxy) для round‑robin между ними.
  3. Напишите скрипт нагрузочного теста (например, 1000 запросов параллельно), измерьте p50, p95, p99.
  4. Добавьте квантование AWQ (4‑bit) и повторите тест. Сравните latency и VRAM.
  5. Включите prefix‑caching и повторите; засеките, насколько ускорились запросы с одинаковым префиксом.

Ожидаемый результат Вы получите практическое понимание влияния continuous batching, квантования и балансировки. Сможете объяснить, как настроить production‑инференс под разные нагрузки.


Связь с другими вопросами

ВопросТема
62Как вы оптимизируете latency LLM? (дополняет: кэширование, батчинг)
63Как вы мониторите LLM в production? (observability, метрики)
64Как вы обеспечиваете security при развёртывании LLM? (аутентификация, изоляция)
65Как вы делаете A/B‑тестирование моделей? (сравнение инференс‑серверов)
66Как вы управляете версиями моделей? (работа с множеством экземпляров)
67Как вы выбираете между self‑hosted и API? (стоимость, контроль)

Навигация