Как вы разворачиваете 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 Face | SafeTensors, flash attention, интеграция с HF ecosystem | Простота развёртывания, встроенная поддержка quantisation (bitsandbytes, GPTQ) | Меньше гибкости в управлении памятью, чем vLLM |
| TensorRT-LLM | NVIDIA | TensorRT оптимизации, поддержка многопоточности, in-flight batching | Максимальная производительность на NVIDIA GPU (до 4x ускорение) | Сложность компиляции, привязка к hardware, требуется NVIDIA GPU |
| DeepSpeed (DeepSpeed-MII / Inference) | Microsoft | Zero-оптимизация, инференс через MII | Хорош для very large models (ZeRO‑Inference) | Меньше community adoption, чем vLLM |
Рекомендация для 90% проектов — vLLM. Он прост в настройке, поддерживает гибридное квантование, легко интегрируется с Kubernetes и даёт отличный throughput.
Ключевой механизм: Paged attention
- Разделяет KV-cache на блоки, аналогично виртуальной памяти в ОС
- Позволяет эффективно использовать видеопамять, избегая её фрагментации
- Увеличивает throughput в 2–4x по сравнению с vanilla transformers
Continuous batching — сервер может динамически добавлять новые запросы в батч, пока предыдущие ещё генерируются, без ожидания окончания всех текущих.
3. Оборудование: выбор GPU и RAM
Выбор GPU зависит от размера модели, требуемой latency и бюджета.
| Модель | Размер | Рекомендованная GPU | VRAM (min) | VRAM (комфортно) | Пример throughput (vLLM) |
|---|---|---|---|---|---|
| Llama‑3‑8B | 8B | L4 (24GB), A10G (24GB) | 16GB | 24GB | 50–100 req/s (batch=16) |
| Llama‑3‑70B | 70B | A100‑80GB, H100‑80GB | 140GB (квантование 4‑bit: 35GB) | 80GB (FP16) | 10–20 req/s (batch=8) |
| Mixtral 8x7B | ~47B | A100‑80GB, H100 | 90GB (FP16) или 48GB (4‑bit) | 80GB | 20–30 req/s |
| GPT‑J‑6B | 6B | T4 (16GB), L4 | 12GB | 16GB | 100–150 req/s |
Важно учитывайте не только модель, но и KV-cache — для контекстной длины 8K и batch=16 он может потребовать дополнительно 2–8GB.
CPU RAM — обычно 32–64GB для ОС и обработки данных, но для больших моделей может потребоваться больше (особенно при загрузке через CPU‑offload).
4. Квантование (Quantisation)
Квантование — снижение точности весов модели (например, с FP16 до INT4), что уменьшает потребление памяти и ускоряет инференс на современных GPU (поддержка тензорных ядер INT4/INT8).
| Тип | Битность | Эффект на качество | Скорость (vs FP16) | Примечание |
|---|---|---|---|---|
| FP16 | 16 | Эталон | 1x | Требует много VRAM |
| INT8 | 8 | Минимальная потеря | ~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.
- 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"]
- 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 | Процент занятости GPU | DCGM 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.
Оборудование
Команда запуска
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 fragmentation | Paged 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 для нагрузочного теста
Шаги:
- Запустите два контейнера vLLM на разных портах (8001, 8002) с одной моделью.
- Сконфигурируйте Nginx (или HAProxy) для round‑robin между ними.
- Напишите скрипт нагрузочного теста (например, 1000 запросов параллельно), измерьте p50, p95, p99.
- Добавьте квантование AWQ (4‑bit) и повторите тест. Сравните latency и VRAM.
- Включите prefix‑caching и повторите; засеките, насколько ускорились запросы с одинаковым префиксом.
Ожидаемый результат Вы получите практическое понимание влияния continuous batching, квантования и балансировки. Сможете объяснить, как настроить production‑инференс под разные нагрузки.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 62 | Как вы оптимизируете latency LLM? (дополняет: кэширование, батчинг) |
| 63 | Как вы мониторите LLM в production? (observability, метрики) |
| 64 | Как вы обеспечиваете security при развёртывании LLM? (аутентификация, изоляция) |
| 65 | Как вы делаете A/B‑тестирование моделей? (сравнение инференс‑серверов) |
| 66 | Как вы управляете версиями моделей? (работа с множеством экземпляров) |
| 67 | Как вы выбираете между self‑hosted и API? (стоимость, контроль) |
Навигация
- Предыдущий: 60
- Следующий: 62
- Индекс: 00. Индекс разборов