AI-инжиниринг
Model Serving: деплой моделей в production - TGI, vLLM, Triton, SageMaker
Цели урока
- Выбирать inference framework для конкретного сценария: Ollama / TGI / vLLM / Triton
- Деплоить LLM через TGI и vLLM в Docker с production-ready конфигурацией
- Понимать continuous batching и PagedAttention - ключевые оптимизации для high throughput
- Настраивать autoscaling GPU workloads в Kubernetes с учётом cold start (2 мин) проблемы
- Мониторить inference servers: TTFT, TPS, KV-cache utilization, GPU health
vLLM увеличивает throughput в 24x по сравнению с наивным inference через PagedAttention. Это как разница между блокирующим I/O и async. Только для GPU памяти. Один Ollama-контейнер падает при 50 concurrent requests. vLLM обрабатывает 1400 tok/s на том же A100 при 128 concurrent users. Autoscaling на spot instances - 70% экономии на GPU. И всё это - без смены модели, без fine-tuning, только правильная serving-инфраструктура.
- HuggingFace TGI обслуживает ChatUI для 30K+ concurrent users на кластере H100 - continuous batching как основа
- Perplexity AI: 100M+ запросов в месяц на vLLM, PagedAttention сократил GPU-парк на 60% без потери throughput
- Kwon et al. 2023 (UC Berkeley) - оригинальный vLLM/PagedAttention paper, throughput 24x vs naive подход
- Один неоптимизированный inference server стоит 10 000 долларов/мес; оптимизированный - 2 000 при том же throughput
- P99 TTFT <200ms - требование финтех и healthcare: каждая секунда задержки стоит прямых денег
PagedAttention: как студенты Berkeley изменили inference
Июнь 2023. Woosuk Kwon, Zhuohan Li и коллеги из UC Berkeley публикуют "Efficient Memory Management for Large Language Model Serving with PagedAttention". Идея простая до гениальности: управлять KV-cache как виртуальными страницами памяти - ровно как OS управляет RAM с 1960-х. До этого каждый запрос резервировал максимальный блок памяти заранее, независимо от реальной длины генерации. 70% VRAM уходило впустую. PagedAttention выделяет страницы по мере необходимости, освобождает сразу после завершения. Результат: 24x throughput на одном GPU. vLLM вышел как open-source implementation - за несколько месяцев стал де-факто стандартом production inference.
Предварительные знания
Serving landscape: TGI, vLLM, Triton, managed services
Запустить модель через Ollama на ноутбуке - пять минут. Обслужить 10 000 concurrent users с SLA 99.9% и p99 latency меньше двух секунд - совсем другая история. Разрыв между этими двумя мирами называется **model serving** - инфраструктурный слой между весами модели и production трафиком.
Наивный деплой (один Docker-контейнер с Ollama) падает при 50 concurrent запросах. Не потому что модель плохая. Потому что Ollama обрабатывает запросы **последовательно** - без continuous batching, без PagedAttention, без KV-cache management. Это как блокирующий I/O вместо async: один запрос занял GPU, остальные ждут в очереди.
**Ключевые требования production serving:**
- **High throughput** - сотни-тысячи requests per second на минимальном количестве GPU
- **Low latency** - time to first token <200ms, end-to-end <2-5s для типичного ответа
- **Horizontal scaling** - добавление GPU нод при росте нагрузки
- **Health checks & graceful shutdown** - zero-downtime deploys
- **Monitoring** - token throughput, queue depth, GPU utilization, error rate
- **Model versioning** - A/B testing, canary deploys, rollback
**Основные inference frameworks:**
| Framework | Компания | Ключевая фича | Лучше всего для | Сложность |
|---|---|---|---|---|
| vLLM | UC Berkeley → community | PagedAttention, continuous batching | Pure LLM serving, max throughput | Средняя |
| TGI (Text Generation Inference) | HuggingFace | Production-ready из коробки, metrics | HF ecosystem, Docker deploy | Низкая |
| Triton Inference Server | NVIDIA | Multi-model, multi-framework | Гетерогенные workloads (LLM + CV + audio) | Высокая |
| TensorRT-LLM | NVIDIA | Max performance на NVIDIA GPU | Когда каждая ms критична | Высокая |
| Ollama | Community | Простота | Dev, demo, small production | Очень низкая |
| SageMaker Endpoints | AWS | Managed, auto-scaling | AWS-first компании | Низкая (но дорого) |
| Ray Serve | Anyscale | Distributed computing | Сложные pipelines, multi-model |
TGI: production deployment с Docker
**Text Generation Inference (TGI)** от HuggingFace - наиболее "batteries-included" решение на рынке. Один Docker-контейнер даёт: Prometheus metrics, health endpoints, OpenAI-compatible API, flash attention, quantization (AWQ, GPTQ), tensor parallelism на нескольких GPU. Никакого boilerplate - всё из коробки.
Команда запуска выглядит длинно, но каждый флаг важен. `--max-concurrent-requests 128` - это мягкий лимит очереди, не жёсткий cap. `--quantize awq` режет VRAM в 2x без заметной потери качества. `--num-shard 2` включает tensor parallelism для 70B моделей, которые не влезают в один GPU.
**Docker Compose для production с мониторингом:**
**Интеграция с Node.js backend** - TGI предоставляет OpenAI-compatible endpoint:
**TGI vs raw vLLM Docker:** TGI имеет встроенные Prometheus metrics, structured logging, watermarking support и лучшую документацию. vLLM имеет чуть выше raw throughput. Для большинства production deployments разница не критична - оба работают отлично.
В docker-compose.yml для TGI стоит start_period: 120s в healthcheck. Зачем?
vLLM: continuous batching и оптимизация throughput
2023 год. Woosuk Kwon и команда из UC Berkeley публикуют paper "Efficient Memory Management for Large Language Model Serving with PagedAttention". Основная идея: KV-cache хранится как виртуальные страницы памяти - ровно как OS управляет RAM. Результат - throughput растёт в 24x по сравнению с наивным inference при той же hardware.
Это как разница между блокирующим I/O и async. Только для GPU памяти.
**PagedAttention в деталях:**
Вторая инновация - **continuous batching**. Обычный static batching ждёт пока весь batch закончит генерацию, прежде чем взять новые запросы. Continuous batching добавляет новые запросы в batch сразу, как только освобождается слот. GPU никогда не простаивает.
**Production deployment vLLM** с оптимальными параметрами:
**Бенчмарк throughput** (Llama 3.1 8B, A100 80GB):
| Concurrent requests | Ollama (tok/s total) | vLLM (tok/s total) | TGI (tok/s total) |
|---|---|---|---|
| 1 | 55 | 50 | 48 |
| 4 | 55 | 180 | 165 |
| 16 | 55 | 520 | 470 |
| 32 | 52 | 860 | 750 |
| 64 | 48 (queue!) | 1200 | 1050 |
| 128 | timeout | 1400 | 1200 |
**Prefix caching** - оптимизация для повторяющихся system prompts. Если все запросы начинаются одинаково (system prompt, few-shot examples), vLLM вычисляет KV-cache для этого prefix один раз и переиспользует:
**Ollama throughput не растёт с concurrency** - у него нет continuous batching. При 64 concurrent requests Ollama обрабатывает их последовательно (~48 tok/s total), а vLLM - параллельно (~1200 tok/s total). Для production с >10 concurrent users - vLLM или TGI обязательны.
Один GPU обрабатывает один запрос за раз - остальные ждут в очереди
Continuous batching обрабатывает множество запросов одновременно - новый запрос занимает слот немедленно после завершения предыдущего, без ожидания всего batch
Static batching (как в Ollama) действительно обрабатывает запросы почти последовательно: ждёт завершения текущей группы, потом берёт следующую. Continuous batching (vLLM, TGI) работает как async I/O: каждый freed slot мгновенно получает новый запрос. При 64 concurrent users разница - 48 tok/s vs 1200 tok/s на одном A100.
vLLM с --enable-prefix-caching обслуживает чатбот. Все 1000 запросов в минуту имеют одинаковый system prompt (500 токенов). Сколько раз vLLM обработает этот system prompt?
Autoscaling GPU: Kubernetes, spot instances, cold start
LLM inference имеет характерный паттерн нагрузки: **spiky traffic** - пиковые часы в 5-10x выше среднего. Держать GPU под пиковую нагрузку 24/7 - прямые деньги на ветер. Autoscaling позволяет платить только за реально используемые ресурсы. Экономия на A100 кластере из 4 GPU - от 3 000 до 50 000 долларов в месяц в зависимости от масштаба.
**Проблема GPU autoscaling:** в отличие от CPU-workloads, LLM pods стартуют **медленно** - 1-3 минуты на загрузку модели в GPU. Стандартный HPA (Horizontal Pod Autoscaler) реагирует через ~60 секунд, pod поднимается ещё 120 секунд. Traffic spike прошёл, пользователи получили timeout-ы, pod только что поднялся.
**Kubernetes deployment с HPA:**
**Spot/preemptible instances** - экономия 60-70% на GPU:
| GPU | On-Demand ($/hr) | Spot ($/hr) | Savings |
|---|---|---|---|
| NVIDIA L4 | 0.70 | 0.24 | 66% |
| NVIDIA A100 40GB | 3.67 | 1.10 | 70% |
| NVIDIA A100 80GB | 4.38 | 1.31 | 70% |
| NVIDIA H100 | 8.50 | 2.55 | 70% |
**Spot instances могут быть забраны** с 30s предупреждением. Текущие запросы прерываются. Решение: graceful shutdown handler (завершить текущие, не брать новые), retry middleware на клиенте, fallback на cloud API.
LLM serving pod на Kubernetes стартует 2 минуты (загрузка модели). Traffic spike случается за 30 секунд. Какая стратегия лучше?
Monitoring inference servers: метрики, алерты, debugging
LLM inference server - не обычный HTTP-сервис. GPU стоит 1-10 долларов в час. Если GPU утилизирован на 30% вместо 80% - это не просто неэффективность, это прямые деньги. Один неоптимизированный inference сервер с A100 стоит 10 000 долларов в месяц. Оптимизированный при том же throughput - 2 000.
Специфика inference мониторинга: обычные метрики (CPU, memory, error rate) не скажут ничего полезного. Нужны **tokens/s**, **KV-cache utilization**, **TTFT**, **avg batch size**. Именно они показывают реальное состояние системы - за секунды до OOM или throughput деградации.
**Ключевые метрики:**
| Метрика | Что измеряет | Healthy range | Alert threshold |
|---|---|---|---|
| TTFT (Time to First Token) | Задержка до первого токена | <200ms | >500ms (p95) |
| TPS (Tokens per Second) | Скорость генерации | 50-150 tok/s per GPU | <30 tok/s |
| Request queue depth | Очередь ожидающих запросов | 0-10 | >50 (scale up!) |
| GPU utilization | Загрузка GPU compute | 60-90% | <30% (over-provisioned) или >95% (throttling) |
| GPU memory used | Использование VRAM | 80-90% | >95% (OOM risk) |
| KV-cache utilization | Заполненность KV-cache | 50-80% | >90% (preemption risk) |
| Request error rate | Процент ошибок | <0.1% | >1% |
| Avg batch size | Средний размер batch | зависит от нагрузки | Всегда 1 = no batching (проблема) |
**Custom monitoring middleware** для Node.js backend:
**Типичные failure modes** и их диагностика:
| Симптом | Причина | Диагностика | Решение |
|---|---|---|---|
| TTFT вырос в 10x | GPU throttling (перегрев >83°C) | nvidia-smi -q | Улучшить охлаждение, снизить batch size |
| Все запросы timeout | OOM - модель вылетела | dmesg | grep oom | Уменьшить max-model-len или max-num-seqs |
| Throughput упал на 50% |
Один GPU обрабатывает один LLM-запрос за раз - остальные просто ждут
Continuous batching позволяет GPU обрабатывать десятки запросов одновременно: новый запрос занимает освободившийся слот немедленно, не дожидаясь завершения всего batch
Интуиция из CPU-мира (поток = один запрос) не переносится на GPU inference. GPU - massively parallel: сотни SM (streaming multiprocessors) могут работать над разными sequence в одном forward pass. Continuous batching использует это: как только запрос А закончил генерацию, его слот в KV-cache освобождается и туда немедленно заходит запрос D. Без ожидания. При 64 concurrent users Ollama (без CB) даёт 48 tok/s. vLLM (с CB) - 1200 tok/s. Разрыв в 25x.
Итоги
- Serving landscape: Ollama (dev) → TGI (simple production) → vLLM (max throughput) → Triton (multi-model)
- TGI: Docker one-liner, Prometheus metrics, health endpoints - batteries-included production deploy
- vLLM (Kwon et al. 2023): PagedAttention (95% memory utilization) + continuous batching = 24x throughput vs naive
- Prefix caching: shared system prompt вычисляется 1 раз → огромная экономия при повторяющихся prompts
- GPU autoscaling: predictive (cron) + warm standby + queue buffer - покрытие cold start (2 мин pod startup)
- Spot instances: 60-70% экономия, нужен graceful shutdown, retry middleware и fallback на cloud API
- Мониторинг: TTFT (p95 <500ms), TPS (>30/GPU), queue depth (<50), KV-cache (<90%)
Вопросы для размышления
- PagedAttention решает проблему VRAM фрагментации через virtual memory. Какие ещё паттерны из OS можно применить к LLM inference - например, swap, huge pages, memory-mapped files?
- Throughput vs latency tradeoff: больший batch size увеличивает throughput, но TTFT растёт. Как выбрать оптимальный max-num-seqs для сервиса с SLA на p99 latency <500ms при неравномерной нагрузке?
- Speculative decoding (draft model генерирует токены, основная верифицирует) теоретически снижает latency без потери качества. Почему его не используют по умолчанию в vLLM/TGI?
Что дальше
Model serving - финальный элемент ML infrastructure. Дальше - системный дизайн и специализированные применения.
- AI System Design — Model serving как часть end-to-end AI системы: routing, caching, serving, monitoring
- Cost Management — Оптимизация GPU costs через spot instances, quantization, model routing
- Observability — Inference monitoring как часть общей observability strategy для AI-систем
Связанные уроки
- aie-39-local-models — Serving масштабирует локальный inference в продакшен
- aie-42-ai-system-design — Serving - ключевой компонент AI-системы
- aie-29-cost-management — Батчинг и загрузка GPU определяют стоимость serving
- aie-35-observability — Мониторим latency и throughput в serving
- ml-46-model-serving — Те же паттерны serving для ML-моделей
- sd-03-scalability