vLLM: быстрый сервинг LLM и PagedAttention
Задача страницы. Показать, как поднять vLLM на облачных GPU, настроить PagedAttention, батчинг/стриминг и кэш префиксов, спланировать TPS/латентность и стоимость.
TL;DR
- PagedAttention даёт «виртуальную память» для KV‑кэша → меньше фрагментации, больше одновременных сессий.
- Continuous batching: vLLM динамически добавляет/удаляет запросы на каждом шаге декода → высокий TPS без «холостых» простоев.
- Prefix‑кэш: общий системный промпт/инструкции считаются один раз и переиспользуются.
- Для низкой цены за 1M токенов — квантизация + агрессивный батчинг; для низкой p95 — ограничиваем длины, держим тёплый кэш, повышаем приоритет стриминга.
Когда выбирать vLLM
- Нужен максимальный TPS при умеренной латентности (чат‑сервисы, РАГ‑API, массовая генерация).
- Большой пул одновременных запросов и общие префиксы (системные подсказки/инструкции).
- Требуется стриминг токенов (SSE/WebSocket) и OpenAI‑совместимый HTTP‑интерфейс.
Альтернативы: /solutions/llm-inference/tensorrt-llm/ для минимальной p95, /solutions/llm-inference/tgi/ для «универсального» REST, /solutions/llm-inference/llama-cpp/ для тонких инстансов.
Быстрый старт (один узел)
Запуск сервера
vllm serve meta-llama/Llama-3-8B
--port 8000
--tensor-parallel-size 1
--dtype bfloat16
--max-model-len 8192
--gpu-memory-utilization 0.90
--enable-prefix-caching
--enforce-eager
--served-model-name llama3-8b
Пояснения по ключам:
- --tensor-parallel-size — распараллеливание весов по нескольким GPU узла.
- --dtype — тип весов; на Ampere/Hopper обычно bf16/fp16.
- --max-model-len — лимит суммарного контекста (вход+выход).
- --gpu-memory-utilization — целевая доля HBM под веса+кэш.
- --enable-prefix-caching — кэширование общих префиксов.
- --enforce-eager — быстрый старт без долгих граф‑компиляций.
Пример запроса (стриминг SSE)
curl -N http://localhost:8000/v1/chat/completions
-H "Content-Type: application/json"
-d '{
"model": "llama3-8b",
"messages": [{"role":"system","content":"You are a helpful assistant"},
{"role":"user","content":"Объясни attention простыми словами"}],
"stream": true,
"temperature": 0.2,
"max_tokens": 300
}'
Python‑клиент (OpenAI‑совместимый)
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="unused")
resp = client.chat.completions.create(
model="llama3-8b",
messages=[{"role":"user","content":"Кратко про PagedAttention"}],
stream=True
)
for chunk in resp: print(chunk.choices[0].delta.content or "", end="", flush=True)
Как работает PagedAttention (и почему это быстрее) Классический KV‑кэш растёт ~линейно от длины контекста и числа сессий и легко фрагментируется (память занята «дырками»).
PagedAttention разбивает KV‑кэш на фиксированные блоки («страницы») и управляет ими как виртуальной памятью:
- меньше фрагментации → больше активных сессий в той же VRAM;
- быстрая эвикция/реплейсмент блоков;
- более предсказуемая латентность на больших пулах запросов.
Практика: держите общий системный префикс и шаблоны промптов одинаковыми — так префикс‑кэш в vLLM срабатывает максимально часто.
Батчинг и планировщик vLLM использует continuous batching: на каждом шаге декода планировщик пересобирает батч из активных последовательностей, добивая GPU до целевого заполнения.
Ключевые параметры (ориентиры):
- Размер «эффективного» батча на декоде растёт с числом одновременных запросов.
- Ограничивайте длины контекста (--max-model-len) и максимальный выход (max_tokens в запросе), чтобы не «зажимать» декод длинными сессиями.
- Для высоких QPS: отдайте приоритет мелким/средним запросам, а длинные — через отдельный пул.
Полезные приёмы:
- Группируйте запросы по схожей длине входа (prefill) — это повышает утилизацию на первых шагах.
- Для «длинных» приложений (аналитика/программирование) — применяйте prefix‑кэш, чтобы prefill не «съедал» львиную долю времени.
Память на инференсе: прикидка KV‑кэша
Для LLM с L слоёв и H голов на d‑размерных ключах/значениях, приблизительная память KV:
KV_bytes ≈ 2 * L * (L_in + L_out_avg) * H * d * bytes_per_elem
где коэффициент 2 — для K и V. Снижаем память:
-
уменьшить max-model-len (или жёстко ограничить max_tokens);
-
включить paged‑KV (встроено), держать общие префиксы;
-
по возможности — хранить KV в более «лёгком» dtype (если конфигурация поддерживает);
-
изолировать «длинные» запросы в отдельный пул или на отдельный инстанс. Квантизация, адаптеры и мульти‑модель
-
Квантизация весов (INT4/INT8/AWQ/GPTQ) снижают цену за 1M токенов; проверяйте совместимость модели/режима при запуске.
-
LoRA‑адаптеры: можно держать несколько адаптеров поверх одной базы (горячая смена домена/стиля) — удобно для мульти‑тенантного сервинга.
-
Мульти‑модельный пул: разделите VRAM между несколькими весами или держите «горячую» одну модель + «тёплый» вторичный набор.
Связанные разделы: /solutions/llm-inference/quantization/, /solutions/llm-inference/multi-model/, /solutions/llm-inference/agents/.
Профили конфигураций (ориентиры)
A) «Минимальная цена за 1M токенов» (массовый TPS)
- Квантизация (INT8/INT4), --gpu-memory-utilization 0.90–0.95, высокий пул одновременных запросов, строгие лимиты max_tokens.
- Prefix‑кэш включён; «длинные» сценарии вынесены на отдельный пул.
B) «Сбалансированный»
- bf16/fp16, --gpu-memory-utilization 0.85–0.9, разумные лимиты контекста, префикс‑кэш, приоритет стриминга.
C) «Низкая p95»
- Жёсткие лимиты на длины (короткие ответы), отдельный пул для «длинных», больше GPU на меньшее число одновременных сессий, тщательная настройка тайм‑аутов.
Производительность и стоимость: краткая методикаСнимите реальные TPS_decode и prefill_rate на тестовом трафике.
Оцените латентность запроса: T ≈ (L_in / prefill_rate) + (L_out / (TPS_decode / B)) + overhead
Прикиньте QPS и стоимость за 1M токенов: QPS ≈ B / T
Cost_per_1M ≈ (GPU_hour_price × Num_GPU) / (TPS_decode × 3600 / 1e6)
Подберите лимиты max_tokens, размер пулов и число GPU до выполнения SLA.
Дополнительно: /solutions/llm-inference/costs/, /solutions/cost-planner/.
Мониторинг, алерты, логи
Минимальный набор метрик:
- Latency p50/p95/p99, TPS_decode, prefill_rate, доля timeouts/errors.
- GPU: utilization, HBM usage, «давление» на KV‑кэш (число активных сессий, доля эвикций).
- Кэш: hit‑rate prefix‑кэша, доля повторно используемых префиксов.
- Система: CPU (токенизация), сеть (стриминг), диск (логи/кэш).
Смотрите: /solutions/monitoring-logging/, /solutions/llm-inference/observability/.
Траблшутинг
- Высокая p95 / «хвосты». Сократите max_model_len/max_tokens, вынесите длинные запросы в отдельный пул, увеличьте размер пула GPU или снизьте конкуренцию.
- GPU‑OOM. Понизьте лимиты длины, уменьшите долю --gpu-memory-utilization, примените квантизацию или распределите модель по нескольким GPU (--tensor-parallel-size).
- Низкий TPS. Увеличьте одновременность, проверьте CPU‑узкие места (токенизация), удостоверьтесь, что стриминг включён и кэш префиксов реально используется.
- «Пила» латентности на prefill. Укоротите префиксы, унифицируйте системные подсказки (для кэша), используйте «тёплую» загрузку модели при рестартах.
- Нестабильность после обновления образа. Зафиксируйте версии CUDA/драйвера и контейнеров, прогоните короткий нагрузочный тест перед переключением трафика.
Как это запускать в cloudcompute.ru
- В разделе /solutions/templates/ доступен профиль «vLLM‑Serve» (Jupyter/SSH/Docker): – стартовые скрипты serve.sh/healthcheck.sh; – пресеты cost‑optimized / balanced / low‑latency; – включённый стриминг и логи запросов.
- Для многоузловых сценариев/пулов — см. /solutions/llm-inference/multi-model/ и /solutions/multi-gpu/.
- Для настройки квантизации и KPI — /solutions/llm-inference/quantization/, /solutions/llm-inference/costs/.
Чек‑лист перед продом
- Зафиксированы SLA (p95, TPS), лимиты max_tokens и max_model_len.
- Выбран профиль конфигурации (стоимость/баланс/латентность).
- Включены prefix‑кэш и стриминг; шаблоны промптов унифицированы.
- Проверены QPS/TPS на синтетике и на реальном сэмпле трафика.
- Настроены алерты по latency/TPS/KV‑кэшу, включён сбор логов.
- Описан план фоллбеков (вторая модель, деградация длины/температуры/beam).
Навигация по разделу «Инференс LLM»
- Базовая страница: /solutions/llm-inference/
- Альтернативные стеки: → /solutions/llm-inference/tensorrt-llm/ • /solutions/llm-inference/tgi/ • /solutions/llm-inference/sglang/ • /solutions/llm-inference/llama-cpp/
- Производительность/стоимость: → /solutions/llm-inference/quantization/ • /solutions/llm-inference/costs/ • /solutions/llm-inference/streaming/
- Эксплуатация: → /solutions/llm-inference/observability/ • /solutions/llm-inference/guardrails/
Готовы запустить?
Запустить GPU-сервер