Throughput vs Latency: баланс в продакшене
Задача страницы. Дать практичный рецепт, как на https://cloudcompute.ru балансировать пропускную способность (QPS/TPS/FPS) и латентность (TTFT/p95) на GPU‑сервисах: LLM‑инференс, CV/видеоаналитика, рендер/симуляции. Разобрать архитектуры, настройки батчинга/конкурентности, метрики и экономику.
TL;DR
- Онлайн‑интерактив = приоритет латентности, короткие батчи, жёсткое ограничение очередей. Офлайн/массовая генерация = приоритет throughput, агрессивный батчинг и пайплайнинг. См. https://cloudcompute.ru/solutions/interruptible-patterns/.
- Разделяйте префилл/декод (LLM) и ingest/обработку (CV): разные SLO, разные батчеры.
- Динамический батчинг = окно ожидания (Δ) + цели p95: подбирайте Δ так, чтобы TTFT(p95) укладывался в бюджет.
- Микробатчинг + потоковая выдача: отдавайте первые токены/кадры сразу, остальное — батчируйте.
- Считайте всё: Little’s Law (L≈λW), ρ≈λ·S (загрузка), tail‑латентность растёт резко при ρ→1. Наблюдаемость: https://cloudcompute.ru/solutions/monitoring-logging/.
- Экономика: Cost_per_query падает с ростом батча до порога SLO, дальше растёт из‑за штрафов за задержки и ретраи. Планируйте на https://cloudcompute.ru/solutions/cost-planner/.
- GPU‑тюнинг: смешанная точность (BF16/FP8), pinned memory, zero‑copy, KV‑кэш INT8 — см. https://cloudcompute.ru/solutions/fp8-bf16/ и https://cloudcompute.ru/solutions/performance-tuning/.
- Мульти‑GPU: шардинг и роутинг запросов без cross‑GPU блокировок — см. https://cloudcompute.ru/solutions/multi-gpu/.
Сценарии
- LLM‑чат/агенты (On‑Demand): SLO по TTFT и p95‑латентности, микробатчинг с малым окном Δ, стриминг токенов (SSE/WebSocket). См. https://cloudcompute.ru/solutions/gradio-fastapi/.
- API генерации (офлайн/пакеты): большие батчи, длинные окна Δ, прерываемые задания чанками ≤ 120 сек.
- Видеоаналитика RTSP: стабильный FPS, ring‑buffer 200–500 мс, NVDEC/NVENC, drop‑политики.
- RAG/поиск/эмбеддинги: батчируйте запросы эмбеддинга, для поиска — кэш/индексы на GPU.
- Симуляции/цифровые двойники: частота обновления UI/сенсоров важнее общей пропускной — низкое Δ, backpressure в ingest.
Архитектуры/пайплайны A) Онлайн LLM‑сервис (низкая латентность)
Client → API Gateway → Admission Control (слайс по SLO)
→ Scheduler (prefill queue / decode queue)
→ Microbatcher(Δ_small) → GPU Worker(s)
→ SSE/WebSocket (стриминг токенов)
Метрики: TTFT, tps_tok_s, p95 latency, q_len_prefill/decode, gpu_util/hbm
B) Офлайн генерация/аналитика (высокий throughput)
Job Queue → N Executors (Docker)
├─ Batcher(Δ_large)
├─ GPU Worker(s)
└─ NVMe Cache → Хранилище "тёплое/холодное"
Режим: Interruptible, чанк ≤ 120 сек, ретраи, идемпотентность
C) CV/Видео поток (стабильный FPS)
RTSP/USB → Ingest → Ring Buffer → Preprocess (resize/normalize)
→ Microbatcher(кадры×камеры) → GPU Inference
→ Postproc → Event Bus/SSE
Алгоритм drop: oldest/skip‑frame при backlog > порог
D) Мульти‑GPU/мульти‑нод
Router → [Node1 GPU0..k] ... [NodeN GPU0..k]
Политики: sticky по контексту/длине запроса, без cross‑GPU зависимостей
См. также: https://cloudcompute.ru/solutions/performance-tuning/, https://cloudcompute.ru/solutions/multi-gpu/.
Профили GPU / VRAM / ориентиры
Ориентиры для целевой загрузки U≈0.7 и запасе VRAM ≥20%. Реальные значения зависят от модели/сцены/кодека.
| **Профиль** | **Видеопамять** | **LLM (интерактив)** | **Эмбеддинги/батчи** | **Видео/CV** | **Рекомендации** |
| **24 ГБ (Compact)** | 24 ГБ | малые модели, короткий контекст; TTFT приоритет, Δ≤10–20 мс | батчи 16–64, Δ≤50–80 мс | 1080p@30–60, 1–2 потока | On‑Demand/минимальный батч, NVENC ≤ 1–2 сессий |
| **48 ГБ (Balanced)** | 48 ГБ | средние модели, средний контекст; Δ≤30–60 мс | батчи 64–256, Δ≤100–200 мс | 1080p@60 + 1–2 NVENC | Смешанный режим: online + офлайн батчи |
| **80 ГБ (HQ)** | 80 ГБ | крупные модели/4K UI; Δ≤50–100 мс | батчи 256–1k, Δ≤200–400 мс | 4K@30–45, 3–4 NVENC | Максимум throughput, изоляция очередей |
Конфиги и скелеты
1) Модель‑сервер (динамический батчинг, квоты)
model:
name: "service-llm"
batching:
enable: true
preferred_batch_sizes: [4, 8, 16, 32]
max_queue_delay_microseconds: 60000 # Δ = 60 мс для online; 200–400 мс для офлайна
instance_groups:
- kind: "KIND_GPU"
count: 1
scheduling:
priority_levels:
- name: "realtime" # UI/операторские
max_concurrency: 32
- name: "bulk" # офлайн
max_concurrency: 256
limits:
max_pending_requests: 2000
timeout_ms: 5000
2) Политика приёма запросов (FastAPI, SLO‑aware)
from fastapi import FastAPI, Request, HTTPException
import time, asyncio, queue
TARGET_P95_MS = 800
MAX_INFLIGHT = 64 # конкарренси online
Q = asyncio.Semaphore(MAX_INFLIGHT)
app = FastAPI()
@app.middleware("http")
async def admission(request: Request, call_next):
# Бюджет очереди из Little's Law: W≈L/λ. Если backlog растёт — 503.
inflight = MAX_INFLIGHT - Q._value
if inflight > MAX_INFLIGHT * 0.9:
raise HTTPException(503, "busy")
start = time.perf_counter()
async with Q:
resp = await call_next(request)
dt_ms = (time.perf_counter() - start) * 1000
if dt_ms > TARGET_P95_MS:
# сигнал автоскейлеру/батчеру уменьшить Δ
resp.headers["X-SLO-HINT"] = "reduce_delta"
return resp
3) Стриминг токенов (ранний ответ + пайплайнинг)
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
@app.get("/generate")
def generate(prompt: str):
def stream():
# Сразу отправляем первые токены (низкая TTFT)
for tok in llm.generate_stream(prompt, delta_ms=20, max_new_tokens=256):
yield f"data: {tok}nn"
return StreamingResponse(stream(), media_type="text/event-stream")
4) Настройки CV‑батчера (камеры×кадры)
cv_batcher:
max_batch_frames: 32 # суммарно по камерам
max_wait_ms: 30 # удержание под батч ≤ 1 кадра при 30 FPS
drop_policy: "oldest" # при backlog > 3×frame_time
ring_buffer_ms: 300
``` ## **Наблюдаемость, метрики, алерты**
См. <https://cloudcompute.ru/solutions/monitoring-logging/> и <https://cloudcompute.ru/solutions/llm-inference/observability/>.
**Ключевые метрики**
- Очереди: q\_len\_prefill, q\_len\_decode, event\_backlog, inflight.
- Латентность: ttft\_ms (p50/p95), latency\_ms (p50/p95), inter\_token\_ms/tps\_tok\_s.
- Throughput: qps, fps, tokens\_s, batch\_size\_eff.
- GPU: gpu\_util\_pct, gpu\_mem\_used\_gb, sm\_efficiency\_pct, pcie\_tx\_mb\_s, enc\_sessions.
- I/O: i/o\_backlog\_sec, nvme\_write\_mb\_s, net\_rtt\_ms (p95).
- Качество: бизнес‑метрики (accuracy/PSNR/etc) на контрольных наборах.
**Алерты (примеры)**
- ttft\_ms(p95) > SLO 5 мин → сократить Δ, уменьшить batch, увеличить инстансы.
- q\_len\_\* монотонно растёт > N → включить backpressure/503, масштабировать воркеры.
- gpu\_util\_pct < 30% при qps высоком → узкое место вне GPU (I/O/CPU/кодек).
- gpu\_mem\_used\_gb/vram > 0.9 → уменьшить контекст/батч, включить INT8/FP8 (см. <https://cloudcompute.ru/solutions/fp8-bf16/>).
- frame\_drop\_pct > 1% в CV → снизить FPS/битрейт, увеличить ring\_buffer\_ms.
## **Экономика и формулы**
**Сервисные соотношения**
ρ ≈ λ · S # загрузка (λ — запросы/сек, S — среднее время обслуживания)
W ≈ L / λ # Little’s Law: среднее время в системе
Wq растёт ≈ ρ/(1-ρ) # очередь резко растёт при ρ → 1 (инженерная эвристика)
QPS ≈ concurrency / service\_time
**LLM (стоимость токенов)** — см. также <https://cloudcompute.ru/solutions/fp8-bf16/>
EffCostPerHour = (c\_gpu \* N\_gpu) / U
TokensPerHour = TPS\_tok\_s \* 3600 \* N\_gpu
Cost\_per\_1000\_tok = EffCostPerHour / (TokensPerHour / 1000)
TTFT ≈ queue\_delay(Δ) + prefill\_time
**Динамический батчинг**
Latency\_batch ≈ queue\_delay(Δ) + service\_time(batch)
Throughput ↑ с ростом batch, но TTFT ↑ из-за queue\_delay.
Оптимум: минимизировать Cost\_per\_query при TTFT(p95) ≤ SLO.
**CV/Видео (камеры×кадры)**
FPS\_eff ≈ min(FPS\_in, GPU\_capacity(batch, model))
Cost\_per\_camera\_hour ≈ (c\_gpu \* α\_render + c\_gpu \* α\_infer) / U
**Безопасность/политики**
- **Изоляция очередей**: разные priority‑классы (realtime/bulk), лимиты по арендаторам.
- **Rate limiting и admission**: защищает от штормов запросов, предотвращает деградацию tail‑латентности.
- **Ключи/секреты** — только в переменных окружения/секрет‑хранилищах (см. <https://cloudcompute.ru/solutions/security/>).
- **PII/логирование**: не логируйте payload; суммарные метрики вместо сырых данных.
- **Ретеншн**: логи/бэги/трейсы с ротацией, «тёплое/холодное» хранение — <https://cloudcompute.ru/solutions/storage-data/>.
**Траблшутинг**
<table><tbody><tr><td>**Симптом**
</td><td>**Причина**
</td><td>**Решение**
</td></tr><tr><td>TTFT(p95) вырос
</td><td>Окно Δ велико или backlog
</td><td>Уменьшите Δ, лимитируйте inflight, увеличьте воркеры.
</td></tr><tr><td>GPU недогружен при высокой очереди
</td><td>Узкое место I/O/CPU
</td><td>Профилируйте, включите pinned memory/zero‑copy, разгрузите препроцесс.
</td></tr><tr><td>«Пила» латентности
</td><td>Пере‑агрессивный автоскейлинг/батчинг
</td><td>Стабилизируйте Δ, введитесь гистерезис, фиксируйте min/max инстансы.
</td></tr><tr><td>Head‑of‑line blocking
</td><td>Разнородные запросы в одном батче
</td><td>Сегментируйте очереди (по длине контекста/времени запроса).
</td></tr><tr><td>Падение TPS при росте batch
</td><td>VRAM/кэш переполнены
</td><td>Уменьшите batch или dtype KV‑кэша (INT8/FP8), см. /solutions/fp8-bf16/.
</td></tr><tr><td>CV: drop кадров > 1%
</td><td>Малый ring‑buffer, слабый NVENC
</td><td>Увеличьте ring‑buffer, снизьте FPS/битрейт, проверьте NVENC‑сессии.
</td></tr><tr><td>Пики p99
</td><td>Холодный старт, миграции
</td><td>Предпрогрев моделей, пинning воркеров, sticky‑routing.
</td></tr><tr><td>503/таймауты у клиентов
</td><td>Admission слишком жёсткий
</td><td>Разделяйте классы трафика, увеличьте квоты realtime.
</td></tr></tbody></table>
**Как запустить в cloudcompute.ru**
1. **Шаблон** (Docker/SSH/Jupyter): <https://cloudcompute.ru/solutions/templates/>.
2. **Режим**: On‑Demand для UI/чатов (низкое Δ, строгие SLO), Interruptible для батчей (Δ↑, throughput↑). См. <https://cloudcompute.ru/solutions/interruptible-patterns/>.
3. **Профиль GPU**: 24 ГБ / 48 ГБ / 80 ГБ — см. таблицу профилей.
4. **Модель‑сервер**: включите динамический батчинг и приоритизацию; для LLM — разделённые очереди префилл/декод. См. <https://cloudcompute.ru/solutions/triton-inference-server/>.
5. **Наблюдаемость**: экспорт p50/p95, очереди, gpu\_util/hbm — по гайду <https://cloudcompute.ru/solutions/monitoring-logging/> и <https://cloudcompute.ru/solutions/llm-inference/observability/>.
6. **Тюнинг**: BF16/FP8, KV‑кэш INT8, pinned memory — <https://cloudcompute.ru/solutions/fp8-bf16/> и <https://cloudcompute.ru/solutions/performance-tuning/>.
7. **CI/CD**: фиксируйте конфиги Δ/лимитов/версий — <https://cloudcompute.ru/solutions/containers-ci-cd/>.
8. **Хранилище**: NVMe‑кэш и выгрузка в «тёплое/холодное» — <https://cloudcompute.ru/solutions/storage-data/>.
9. **Мульти‑GPU/роутинг**: <https://cloudcompute.ru/solutions/multi-gpu/>.
**Чек‑лист перед продом**
- Определены SLO: TTFT(p95), latency(p95), drop% для каждого класса трафика.
- Настроены очереди/приоритеты и окно Δ; TTFT(p95) в бюджете.
- GPU util 60–85%, VRAM запас ≥ 20%; нет I/O backlog.
- Метрики и алерты подключены; есть дашборды очередей и latency.
- Для LLM — раздельные очереди префилл/декод; для CV — ring‑buffer и drop‑политики.
- Включены BF16/FP8 и KV‑dtype оптимизации (где безопасно).
- Admission/rate limit защищают сервис; предусмотрены 503 с retry‑hint.
- Параметры батчинга/лимитов зафиксированы в CI/CD.
- Экономика подтверждена в <https://cloudcompute.ru/solutions/cost-planner/>.
**Навигация**
- Хаб «Решения»: <https://cloudcompute.ru/solutions/>
- Шаблоны запусков: <https://cloudcompute.ru/solutions/templates/>
- Планирование стоимости: <https://cloudcompute.ru/solutions/cost-planner/>
- Тюнинг производительности: <https://cloudcompute.ru/solutions/performance-tuning/>
- FP8/BF16: <https://cloudcompute.ru/solutions/fp8-bf16/>
- Interruptible‑паттерны: <https://cloudcompute.ru/solutions/interruptible-patterns/>
- Multi‑GPU/Multi‑node: <https://cloudcompute.ru/solutions/multi-gpu/>
- Хранилища/данные: <https://cloudcompute.ru/solutions/storage-data/>
- Наблюдаемость и логи: <https://cloudcompute.ru/solutions/monitoring-logging/>
- Observability для сервисов: <https://cloudcompute.ru/solutions/llm-inference/observability/>
- Сервер инференса: <https://cloudcompute.ru/solutions/triton-inference-server/>
Готовы запустить?
Запустить GPU-сервер