Масштабирование инференса на RTX 4090: как удержать p95 < 300мс под нагрузкой — 4 июля 2026 г. в 12:05:09.960
Масштабирование инференса на RTX 4090: как удержать p95 < 300мс под нагрузкой Локальные LLM в продакшене упираются не в архитектуру, а в управление VRAM и очередь запросов. Одна 4090 с 24 ГБ выдержит Qwen3 или Mistral-Nemo только при оптимизации контекста и грамотной маршрутизации. Если нужен DevOps-инструмент, отвечающий за секунды, забиваем на «просто Ollama» и переходим к детерминированному пайплайну. Проблема кластеров — фрагментация памяти после сессий, промахи KV-cache при разном контексте и латентность префилла. Решение: контейнеризованный vLLM с AWQ, балансировка через Nginx, жёсткий лимит max_num_seqs. Ниже — рабочая схема для 2-3 нод, которую можно адаптировать под корпоративные чат-боты или автоматизацию тикетов. - Архитектура: Client → Nginx (LB + rate limit) → vLLM (3 replicas) → Qdrant (RAG) → Postgres (история). Всё в Docker Compose. Nginx отдаёт трафик round-robin, проверяет /health каждые 10 сек. При падении ноды upstream автоматически исключает её из пула на 30 секунд. - Конфиг vLLM: docker run --gpus all -p 8000:8000 -v /models:/data ghcr.io/vllm/vllm-openai:latest --model Qwen/Qwen2.5-7B-Instruct-AWQ --max-model-len 4096 --gpu-memory-utilization 0.92 --max-num-seqs 16 --swap-space 2. Параметр 0.92 оставляет место под KV-cache, иначе OOM. Флаг --max-num-seqs 16 ограничивает параллельные промпты на GPU, предотвращая деградацию throughput при пиковых нагрузках. - Квантование: AWQ (4-bit) даёт +30% throughput против FP16 с минимальной потерей точности. GGUF/llama.cpp оставляем для CPU-fallback. В GPU-стэке vLLM+AWQ выигрывает за счёт PagedAttention и CUDA-ядер. Для специфичных доменов (документация, код) лучше дообучить адаптеры LoRA через vllm-adapters, не перезагружая базовую модель в память. - Квоты и маршрутизация: В Nginx: limit_req zone=llm burst=20 nodelay;. Режет batch-всплески от CI/CD. Для sticky-сессий используем ip_hash или хедер X-Client-ID, что экономит KV-cache на повторные токены диалога. Конфиг upstream: server 10.0.1.2:8000 max_fails=3 fail_timeout=20s;. - Мониторинг: DCGM exporter + Prometheus. Метрики: dcgm_fi_nvml_gpu_memory_used_bytes, vllm:gpu_cache_usage_perc, http_request_duration_seconds_bucket. Alertmanager правило: {job="vllm"} > 0.85 триггерит webhook в Slack и запускает docker service scale vllm=4. Графика p95 строится через histogram_quantile(0.95, sum(rate(...))). - GC и Retry-логика: vLLM чистит память сам, но для долгих сессий добавляем /v1/models ping для инвалидации. Клиент оборачиваем в retry с exponential backoff (max 3) и timeout 45s. Псевдокод: for i in range(3): try: resp = await client.generate(prompt) break except RateLimitError: await sleep(2**i). - Безопасность: Отключаем внешние API keys. В vLLM: --api-key internal-secret. Валидация через Nginx auth_request. Чекпоинты кэшируем на локальном NVMe, NFS используем только для шары конфигов. TLS между компонентами обязательно, даже в private subnets. Стек держит 60-80 RPS на 7B, пиковая загрузка VRAM не улетает в 100% благодаря PagedAttention. Для контекста >4K режьте utilization до 0.85 и добавляйте ноду в upstream. Локальный инференс становится production-ready, когда вы контролируете очередь, память и метрики на уровне контейнера. #LLMops #vLLM #GPUInfrastructure #DevOpsAI #LocalModels

