NVIDIA Triton: мультифреймворк‑сервинг на GPU
Задача страницы. Развернуть и эксплуатировать NVIDIA Triton на https://cloudcompute.ru для сервинга моделей PyTorch/ONNX/TensorRT/Python‑backend с динамическим батчингом, пайплайнами (Ensemble), приоритизацией трафика и прозрачной наблюдаемостью, не жертвуя SLO и экономикой.
TL;DR
- Triton объединяет разные фреймворки и форматы (TorchScript/ONNX/TensorRT/Python) в единый сервер с динамическим батчингом и Ensemble‑графами.
- Для онлайна (On‑Demand) — низкая латентность, короткое окно batching Δ, стриминг ответов (SSE/WebSocket), раздельные очереди по приоритетам на уровне шлюза. Для офлайна (Interruptible) — длинное Δ, крупные батчи, чанки ≤ 120 сек. См. https://cloudcompute.ru/solutions/interruptible-patterns/.
- Контролируйте баланс throughput vs latency: окно Δ, preferred_batch_size, instance_group, конкуррентность. См. https://cloudcompute.ru/solutions/throughput-vs-latency/.
- Выигрывайте в цене/производительности за счёт BF16/FP8/INT8 (где поддерживается), pinned/zero‑copy. См. https://cloudcompute.ru/solutions/fp8-bf16/ и https://cloudcompute.ru/solutions/performance-tuning/.
- Визуализируйте метрики p50/p95, очереди, GPU util/HBM, кэш‑хиты — см. https://cloudcompute.ru/solutions/monitoring-logging/ и https://cloudcompute.ru/solutions/llm-inference/observability/.
- Храните модели/артефакты на NVMe, разгружайте в «тёплое/холодное» — см. https://cloudcompute.ru/solutions/storage-data/.
- Масштабируйте по мульти‑GPU/мульти‑нод без cross‑GPU блокировок — см. https://cloudcompute.ru/solutions/multi-gpu/.
- Экономика: считайте Cost_per_query, Cost_per_1M_tokens/frames от c_gpu, целевой загрузки U, TPS/FPS — см. https://cloudcompute.ru/solutions/cost-planner/.
Сценарии
- LLM‑инференс: префилл/декод как отдельные модели/инстансы, микробатчинг, стриминг токенов.
- CV/видеоаналитика: батчирование кадров×камер, NVDEC→предобработка→инференс→постпроцесс.
- Классический ML‑скoring: ONNX/TensorRT для низкой латентности, Python‑backend для лёгкого препроцесса.
- Ensemble‑пайплайны: препроцесс→основная модель→постпроцесс как единый граф.
- A/B и канареечный релиз: две версии модели в одном репозитории, роутинг на уровне шлюза.
- Edge‑экспорт/общее хранилище моделей: единый репозиторий, промо через CI/CD.
Архитектуры/пайплайны A) Онлайн LLM (низкая латентность)
Клиент → API Gateway (приоритеты, rate limit)
→ Triton: prefill_model (Δ_small, 1–2 инстанса/GPU)
→ Triton: decode_model (высокая конкуррентность)
→ SSE/WebSocket (стриминг токенов)
Метрики: TTFT, p95 latency, tokens/s, q_len_prefill/decode, gpu_util/hbm
B) CV пайплайн через Ensemble
RTSP → NVDEC → Preprocess(Python backend)
→ Detect(ONNX/TensorRT)
→ Postprocess(Python backend) → Event Bus/SSE
C) Офлайн‑батчи (высокий throughput, Interruptible)
Job Queue → N×Triton Executors (Docker)
├─ Δ_large batching
├─ локальный NVMe кэш
└─ выгрузка результатов в "тёплое/холодное"
См. также: https://cloudcompute.ru/solutions/throughput-vs-latency/, https://cloudcompute.ru/solutions/performance-tuning/, https://cloudcompute.ru/solutions/multi-gpu/.
Профили GPU / VRAM / ориентиры
| **Профиль** | **Видеопамять** | **LLM/текст** | **CV/видео** | **Мульти‑модель** | **Рекомендации** |
| **24 ГБ (Compact)** | 24 ГБ | малые/средние модели, короткий контекст | 1080p@30–60, 1–2 потока | 1–2 модели | Δ≤20–40 мс, 1 инстанс/модель, NVENC ≤2 |
| **48 ГБ (Balanced)** | 48 ГБ | средние модели, несколько клиентов | 1080p@60, 2–3 потока | 2–4 модели | Δ≤40–80 мс, 2 инстанса/модель, batch 32–128 |
| **80 ГБ (HQ)** | 80 ГБ | крупные модели/длинный контекст | 4K@30–45, 3–4 потока | 4–6 моделей | Δ≤80–120 мс, 2–3 инстанса, FP8/INT8 кэш |
Держите запас VRAM ≥ 20%. Для сложных пайплайнов разделяйте модели по инстансам/процессам.
Репозиторий моделей: структура
models/
bert/
1/model.onnx
config.pbtxt
detector/
1/model.plan # TensorRT
config.pbtxt
preprocess/
1/model.py # Python backend
config.pbtxt
postprocess/
1/model.py
config.pbtxt
cv_ensemble/
config.pbtxt # без папки версии — Ensemble как маршрут
``` ## **Конфиги и скелеты**
**1) Docker Compose (Triton + модели + шлюз FastAPI)**
version: "3.9" services: triton: image: nvcr.io/nvidia/tritonserver:xx.yy-py3 runtime: nvidia gpus: all command: > tritonserver --model-repository=/models --exit-on-error=false --response-cache=true --http-port=8000 --grpc-port=8001 --metrics-port=8002 environment:
- NVIDIA_VISIBLE_DEVICES=all volumes:
- /data/nvme/models:/models:ro
- /data/nvme/cache:/cache ports: ["8000:8000","8001:8001","8002:8002"] networks: [serving] gateway: image: ghcr.io/your-org/fastapi-gateway:latest environment:
- TRITON_HTTP=http://triton:8000 ports: ["8080:8080"] networks: [serving] networks: serving: {}
**2) ONNX‑модель: config.pbtxt (динамический батчинг)**
name: "bert" backend: "onnxruntime" max_batch_size: 128 input [ { name: "input_ids" data_type: TYPE_INT32 dims: [ -1 ] }, { name: "attention_mask" data_type: TYPE_INT32 dims: [ -1 ] } ] output [ { name: "logits" data_type: TYPE_FP16 dims: [ -1 ] } # FP16 для экономии ] dynamic_batching { preferred_batch_size: [ 4, 8, 16, 32, 64 ] max_queue_delay_microseconds: 60000 # Δ = 60 мс (онлайн) } instance_group [ { kind: KIND_GPU, count: 1 } ] response_cache { enable: true }
**3) TensorRT‑модель: config.pbtxt (высокий throughput)**
name: "detector" platform: "tensorrt_plan" max_batch_size: 256 input [ { name: "images" data_type: TYPE_FP16 dims: [ 3, -1, -1 ] } ] output [ { name: "boxes" data_type: TYPE_FP16 dims: [ -1, 4 ] }, { name: "scores" data_type: TYPE_FP16 dims: [ -1 ] }, { name: "labels" data_type: TYPE_INT32 dims: [ -1 ] } ] dynamic_batching { preferred_batch_size: [ 8, 16, 32, 64, 128 ] max_queue_delay_microseconds: 120000 # Δ = 120 мс (офлайн) } instance_group [ { kind: KIND_GPU, count: 2 } # два инстанса на GPU ]
**4) Python‑backend (препроцесс) preprocess/config.pbtxt**
name: "preprocess" backend: "python" max_batch_size: 128 input [{ name: "image_bytes", data_type: TYPE_UINT8, dims: [ -1 ] }] output [{ name: "images", data_type: TYPE_FP16, dims: [ 3, 640, 640 ] }]
models/preprocess/1/model.py
import numpy as np import triton_python_backend_utils as pb class TritonPythonModel: def initialize(self, args): pass def execute(self, requests): responses = [] for req in requests: inp = pb.get_input_tensor_by_name(req, "image_bytes") bs = inp.as_numpy() # (batch, bytes) imgs = [] for b in bs:
... декод JPEG/resize/normalize → (3,640,640) FP16
imgs.append(np.zeros((3,640,640), dtype=np.float16)) out = pb.Tensor("images", np.stack(imgs, axis=0)) responses.append(pb.InferenceResponse(output_tensors=[out])) return responses
**5) Ensemble (CV конвейер) cv\_ensemble/config.pbtxt**
name: "cv_ensemble" platform: "ensemble" max_batch_size: 128 input [{ name: "image_bytes", data_type: TYPE_UINT8, dims: [ -1 ] }] output [ { name: "boxes", data_type: TYPE_FP16, dims: [ -1, 4 ] }, { name: "scores", data_type: TYPE_FP16, dims: [ -1 ] }, { name: "labels", data_type: TYPE_INT32, dims: [ -1 ] } ] ensemble_scheduling { step [ { model_name: "preprocess" input_map { key: "image_bytes" value: "image_bytes" } output_map { key: "images" value: "images" } }, { model_name: "detector" input_map { key: "images" value: "images" } output_map { key: "boxes" value: "boxes" } output_map { key: "scores" value: "scores" } output_map { key: "labels" value: "labels" } } ] }
**6) Клиент FastAPI → Triton (HTTP) со стримингом SSE**
from fastapi import FastAPI from fastapi.responses import StreamingResponse import tritonclient.http as http import numpy as np, io TRITON_URL = "http://localhost:8000" cli = http.InferenceServerClient(url=TRITON_URL) app = FastAPI() @app.post("/detect") def detect(image: bytes): inputs = [http.InferInput("image_bytes", [1, len(image)], "UINT8")] inputs[0].set_data_from_numpy(np.frombuffer(image, dtype=np.uint8).reshape(1, -1)) outputs = [http.InferRequestedOutput("boxes"), http.InferRequestedOutput("scores"), http.InferRequestedOutput("labels")] res = cli.infer("cv_ensemble", inputs=inputs, outputs=outputs) return { "boxes": res.as_numpy("boxes").tolist(), "scores": res.as_numpy("scores").tolist(), "labels": res.as_numpy("labels").tolist(), } @app.get("/generate") def generate(prompt: str): def stream():
пример: ранняя отдача токенов; сервер внутри батчит/декодит
for tok in llm_tokens_from_triton(prompt, delta_ms=20): yield f"data: {tok}nn" return StreamingResponse(stream(), media_type="text/event-stream")
## **Наблюдаемость, метрики, алерты**
См. <https://cloudcompute.ru/solutions/monitoring-logging/> и <https://cloudcompute.ru/solutions/llm-inference/observability/>.
**Ключевые**
- Очереди/батчинг: queue\_delay\_ms (p50/p95), batch\_size\_eff, inflight\_requests.
- Латентность: ttft\_ms (для LLM), end\_to\_end\_ms (p50/p95), inter\_token\_ms.
- Throughput: qps, fps, tokens\_s, prefill\_tps/decode\_tps.
- GPU: gpu\_util\_pct, gpu\_mem\_used\_gb (HBM), sm\_efficiency\_pct, pcie\_tx\_mb\_s.
- Кэш: response\_cache\_hit\_ratio, model\_repo\_cache\_hit\_ratio.
- I/O: i/o\_backlog\_sec, nvme\_read\_mb\_s, nvme\_write\_mb\_s.
**Алерты (примеры)**
- ttft\_ms(p95) > SLO → уменьшить Δ, увеличить инстансы модели/нод.
- queue\_delay\_ms ↑ и gpu\_util\_pct < 30% → узкое место вне GPU (I/O/CPU).
- gpu\_mem\_used\_gb/vram > 0.9 → уменьшить batch/контекст или включить BF16/FP8/INT8 (см. <https://cloudcompute.ru/solutions/fp8-bf16/>).
- response\_cache\_hit\_ratio < целевого при повторяющихся запросах → включить/расширить кэш/ttl.
## **Экономика и формулы**
Обозначения: c\_gpu — цена GPU/час; U — целевая загрузка GPU; Δ — окно batching; QPS — запросов/сек; TPS — токенов/сек; t\_h — часы.
**Цена за запрос**
EffCostPerHour = c\_gpu / U
ReqPerHour = QPS \* 3600
Cost\_per\_query = EffCostPerHour / ReqPerHour
**LLM токены**
TokensPerHour = TPS \* 3600
Cost\_per\_1000\_tok = EffCostPerHour / (TokensPerHour / 1000)
**Влияние Δ и батча**
Latency ≈ queue\_delay(Δ) + service\_time(batch)
Throughput ↑ с ростом batch, но TTFT ↑ → ищите минимум Cost\_per\_query при TTFT(p95) ≤ SLO
Планирование — <https://cloudcompute.ru/solutions/cost-planner/>, компромиссы — <https://cloudcompute.ru/solutions/throughput-vs-latency/>.
**Безопасность и политики**
- **Секреты/ключи**: только в секрет‑хранилищах/переменных окружения контейнеров; не логируйте payload. См. <https://cloudcompute.ru/solutions/security/>.
- **PII/ретеншн**: для пользовательских данных — маскирование, ротация/архивация, раздельные среды. См. <https://cloudcompute.ru/solutions/storage-data/>.
- **Изоляция трафика**: классы приоритета (realtime/bulk) и лимиты; anti‑noisy‑neighbor.
- **Сетевой периметр**: ограничьте доступ к портам HTTP/gRPC/metrics, аудит вызовов.
- **Прерываемость**: офлайн‑джобы идемпотентны, чекпоинты ≤ 120 сек. См. <https://cloudcompute.ru/solutions/interruptible-patterns/>.
**Траблшутинг**
<table><tbody><tr><td>**Симптом**
</td><td>**Причина**
</td><td>**Решение**
</td></tr><tr><td>TTFT вырос, p95 деградирует
</td><td>Δ слишком велик, смешение long/short запросов
</td><td>Снизить Δ для префилла, сегментировать очереди, выделить инстансы под long‑контекст.
</td></tr><tr><td>Очередь растёт при низкой GPU util
</td><td>Узкое место I/O/CPU, препроцесс в Python
</td><td>Вынести препроцесс в TensorRT/ONNX, включить pinned/zero‑copy, увеличить vCPU/NVMe.
</td></tr><tr><td>OOM на больших батчах
</td><td>KV/активации в FP16/BF16
</td><td>Снизить batch, включить INT8/FP8 (где доступно), ограничить контекст. См. /solutions/fp8-bf16/.
</td></tr><tr><td>«Пила» латентности
</td><td>Агрессивный автоскейлинг
</td><td>Ввести гистерезис, зафиксировать min/max инстансы, стабилизировать Δ.
</td></tr><tr><td>Не конвертируется модель
</td><td>Несовместимые операторы/динамические размеры
</td><td>Экспорт в другой формат (TorchScript/ONNX), статические размеры, разделение на препроц/инференс.
</td></tr><tr><td>Python‑backend тормозит
</td><td>GIL/интерпретируемые циклы
</td><td>Векторизовать, Numpy/CuPy, вынести в TensorRT/ONNX, распараллелить инстансы.
</td></tr><tr><td>503 на шлюзе
</td><td>Admission защитил SLO
</td><td>Увеличить capacity realtime‑класса, шардировать по нодам, включить кэш ответа.
</td></tr><tr><td>Падение точности при FP8/INT8
</td><td>Квантование критичных узлов
</td><td>Исключить LN/Softmax/Logits из квантизации, калибровать amax. См. <https://cloudcompute.ru/solutions/fp8-bf16/>.
</td></tr></tbody></table>
**Как запустить в cloudcompute.ru**
1. Выберите шаблон (Docker/SSH/Jupyter) на <https://cloudcompute.ru/solutions/templates/>.
2. Подготовьте **репозиторий моделей** на NVMe: models/… как в примере, версионирование/манифест.
3. Выберите **профиль GPU**: 24 ГБ (Compact) / 48 ГБ (Balanced) / 80 ГБ (HQ).
4. Настройте **dynamic batching** (preferred\_batch\_size, max\_queue\_delay) по SLO, разделите онлайновые и офлайновые модели/инстансы. См. <https://cloudcompute.ru/solutions/throughput-vs-latency/>.
5. Включите **mixed precision/кэш** (BF16/FP8/INT8, response cache) — см. <https://cloudcompute.ru/solutions/fp8-bf16/>.
6. Подключите **наблюдаемость** и алерты — <https://cloudcompute.ru/solutions/monitoring-logging/> и <https://cloudcompute.ru/solutions/llm-inference/observability/>.
7. Для масштабирования — **мульти‑GPU/мульти‑нод** и роутер на шлюзе — <https://cloudcompute.ru/solutions/multi-gpu/>.
8. Зафиксируйте конфиги в CI/CD и промоутируйте версии — <https://cloudcompute.ru/solutions/containers-ci-cd/>.
9. Проверяйте экономику через <https://cloudcompute.ru/solutions/cost-planner/>.
**Чек‑лист перед продом**
- SLO: TTFT(p95), latency(p95), QPS/FPS/TPS определены и проверены.
- Δ и preferred\_batch\_size настроены, очереди стабильны, нет head‑of‑line blocking.
- GPU util 60–85%, запас VRAM ≥ 20%; I/O backlog отсутствует.
- Модели разнесены по инстансам/приоритетам; офлайн — в отдельный пул.
- Кэш ответов/моделей включён и даёт целевой hit‑ratio.
- Метрики/алерты/трейсы доступны; логи чисты от PII.
- Mixed precision (BF16/FP8/INT8) включена там, где качество не проседает.
- Репозиторий моделей версионирован; промо через CI/CD.
- Экономика подтверждена: Cost\_per\_query/Cost\_per\_1M\_tokens в бюджете.
**Навигация**
- Хаб «Решения»: <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/>
- Throughput vs Latency: <https://cloudcompute.ru/solutions/throughput-vs-latency/>
- 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/>
- Gradio/FastAPI (стриминг UI): <https://cloudcompute.ru/solutions/gradio-fastapi/>
- Контейнеры и CI/CD: <https://cloudcompute.ru/solutions/containers-ci-cd/>
Готовы запустить?
Запустить GPU-сервер