Aller au contenu

📊 Monitoring de la stack d'infĂ©rence


Architecture de monitoring

flowchart TD
    subgraph Sources["Sources de métriques"]
        A["vLLM /metrics"]
        B["nvidia-smi"] --> C["nvidia-dcgm-exporter"]
        D["OS"] --> E["node-exporter"]
    end
    Sources --> P["Prometheus\n(scrape + store)"]
    P --> G["Grafana\n(dashboards + alertes)"]

1. Stack Docker Compose complĂšte

docker-compose.monitoring.yml
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
ports:
- "9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana-oss:latest
container_name: grafana
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=changeme
- GF_USERS_ALLOW_SIGN_UP=false
ports:
- "3000:3000"
restart: unless-stopped
depends_on:
- prometheus
nvidia-dcgm-exporter:
image: nvcr.io/nvidia/k8s/dcgm-exporter:latest
container_name: dcgm-exporter
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=all
ports:
- "9400:9400"
restart: unless-stopped
cap_add:
- SYS_ADMIN
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
ports:
- "9100:9100"
restart: unless-stopped
volumes:
prometheus_data:
grafana_data:
FenĂȘtre de terminal
docker compose -f docker-compose.monitoring.yml up -d

2. Configuration Prometheus

prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'vllm'
static_configs:
- targets: ['host.docker.internal:8000'] # adapter si vLLM sur autre machine
metrics_path: '/metrics'
- job_name: 'nvidia-gpu'
static_configs:
- targets: ['dcgm-exporter:9400']
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
# Si Ollama (pas de /metrics natif — utiliser l'exporter communautaire)
- job_name: 'ollama'
static_configs:
- targets: ['host.docker.internal:9462'] # port de l'exporter ollama

3. MĂ©triques vLLM — les essentielles

vLLM expose ses métriques sur GET /metrics1. Voici celles à surveiller en priorité :

DĂ©bit et files d’attente

MĂ©triqueDescriptionSeuil d’alerte
vllm:num_requests_runningRequĂȘtes en cours de traitement> 80% de --max-num-seqs
vllm:num_requests_waitingRequĂȘtes en file d’attente> 0 pendant > 30 s
vllm:avg_generation_throughput_toks_per_sDébit moyen tokens/s< seuil défini par usage
vllm:prompt_tokens_totalTokens de prompt traitĂ©s (cumulĂ©)— (trend)
vllm:generation_tokens_totalTokens gĂ©nĂ©rĂ©s (cumulĂ©)— (trend)

KV Cache

MĂ©triqueDescriptionSeuil d’alerte
vllm:gpu_cache_usage_perc% KV Cache occupé> 90%
vllm:cpu_cache_usage_perc% KV Cache swap CPU> 0 (indique du swap)
vllm:num_preemptions_totalRequĂȘtes prĂ©emptĂ©es (KV Cache plein)> 0 rĂ©gulier

Latences

MétriqueDescription
vllm:time_to_first_token_secondsDistribution TTFT par requĂȘte
vllm:time_per_output_token_secondsLatence par token généré
vllm:e2e_request_latency_secondsLatence end-to-end

4. Métriques GPU (DCGM Exporter)

NVIDIA DCGM Exporter expose des métriques GPU détaillées3 :

MĂ©trique DCGMDescriptionSeuil d’alerte
DCGM_FI_DEV_GPU_UTILUtilisation GPU (%)< 10% pendant > 5 min (gaspillage)
DCGM_FI_DEV_MEM_COPY_UTILUtilisation bus mémoire (%)> 90% soutenu
DCGM_FI_DEV_FB_USEDVRAM utilisée (MiB)> 95% de la VRAM totale
DCGM_FI_DEV_GPU_TEMPTempérature GPU (°C)> 83°C (throttling probable)
DCGM_FI_DEV_POWER_USAGEConsommation (W)> TDP déclaré
DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTALDĂ©bit NVLink (Go/s)— (trend sur clusters)

RequĂȘte Prometheus — VRAM utilisĂ©e par GPU

DCGM_FI_DEV_FB_USED{gpu=~".*"}

5. Dashboards Grafana recommandés

Import depuis Grafana.com

  1. Ouvrir Grafana → Dashboards → Import
  2. Entrer l’ID du dashboard :
DashboardID GrafanaUsage
NVIDIA DCGM Exporter12239GPU utilization, mémoire, température4
Node Exporter Full1860CPU, RAM, réseau, disque hÎte5

Panels essentiels Ă  construire manuellement

Panel “DĂ©bit tokens/s” :

rate(vllm:generation_tokens_total[1m])

Panel “KV Cache %” :

vllm:gpu_cache_usage_perc * 100

Panel “File d’attente” :

vllm:num_requests_waiting

Panel “TTFT P95” (95e percentile) :

histogram_quantile(0.95, rate(vllm:time_to_first_token_seconds_bucket[5m]))

6. Alertes Prometheus

# alerts.yml — Ă  rĂ©fĂ©rencer dans prometheus.yml sous rule_files:
groups:
- name: inference-alerts
rules:
- alert: VLLMKVCacheHigh
expr: vllm:gpu_cache_usage_perc > 0.90
for: 2m
labels:
severity: warning
annotations:
summary: "KV Cache vLLM > 90%"
description: "Le KV Cache est à {{ $value | humanizePercentage }}. Risque de swap ou de préemption."
- alert: VLLMRequestQueueBacklog
expr: vllm:num_requests_waiting > 0
for: 1m
labels:
severity: warning
annotations:
summary: "File d'attente vLLM non vide"
description: "{{ $value }} requĂȘtes en attente depuis plus d'1 minute."
- alert: GPUTemperatureHigh
expr: DCGM_FI_DEV_GPU_TEMP > 83
for: 5m
labels:
severity: critical
annotations:
summary: "GPU {{ $labels.gpu }} en surchauffe"
description: "TempĂ©rature GPU Ă  {{ $value }}°C — throttling probable."
- alert: VRAMAlmostFull
expr: (DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_TOTAL) > 0.95
for: 2m
labels:
severity: critical
annotations:
summary: "VRAM GPU {{ $labels.gpu }} critique"
description: "{{ $value | humanizePercentage }} de VRAM utilisée."

Pour activer les alertes dans Prometheus :

# prometheus.yml — ajouter
rule_files:
- "alerts.yml"
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093'] # si Alertmanager déployé

7. Monitoring Ollama (sans Prometheus natif)

Si vous utilisez Ollama, quelques commandes de monitoring immédiat :

FenĂȘtre de terminal
# ModÚles chargés et VRAM occupée
ollama ps
# Logs en temps réel (incluent les durées de génération)
ollama logs -f
# Métriques dans la réponse API (durées en nanosecondes)
curl -s http://localhost:11434/api/generate \
-d '{"model":"llama3.2","prompt":"test","stream":false}' \
| python3 -c "
import sys, json
r = json.load(sys.stdin)
print(f'TTFT: {r[\"prompt_eval_duration\"]/1e9:.2f}s')
print(f'Génération: {r[\"eval_duration\"]/1e9:.2f}s')
print(f'Débit: {r[\"eval_count\"]/(r[\"eval_duration\"]/1e9):.1f} tok/s')
"

8. Traces vs. MĂ©triques — OpenTelemetry pour les stacks agentiques

Prometheus et Grafana rĂ©pondent Ă  la question “Le serveur va-t-il bien ?”. Ils ne rĂ©pondent pas Ă  “Pourquoi cette requĂȘte a-t-elle pris 30 secondes ?”.

Le problĂšme agentique

Dans un pipeline RAG ou multi-agents, une requĂȘte traverse plusieurs services avant de produire une rĂ©ponse. Si un utilisateur se plaint d’une latence de 30s, Grafana vous dira que le GPU Ă©tait Ă  70% d’utilisation — ce qui ne suffit pas Ă  diagnostiquer la cause. Ce qu’il faut, c’est la trace de la requĂȘte complĂšte :

RequĂȘte utilisateur (30s total)
├── VectorDB Qdrant — 4s (recherche sĂ©mantique)
├── Agent routing — 2s (choix de l'outil)
├── SearXNG web search — 20s (timeout rĂ©seau ⚠)
└── LLM generation — 4s (200 tokens @ 50 tok/s)

Sans traces, l’ingĂ©nieur cherche dans les logs de chaque service sĂ©parĂ©ment. Avec des traces OpenTelemetry, la requĂȘte complĂšte est visualisĂ©e en un seul waterfall dans un outil dĂ©diĂ©.

OpenTelemetry (OTEL) — intĂ©gration native vLLM et LiteLLM

LiteLLM et vLLM supportent OpenTelemetry nativement67 :

FenĂȘtre de terminal
# vLLM — activer OTEL (exporte vers un collector local)
vllm serve meta-llama/Llama-3.1-70B-Instruct \
--otlp-traces-endpoint http://localhost:4317
# LiteLLM — activer dans litellm_config.yaml
general_settings:
otel: true
otel_endpoint: http://localhost:4317 # OTLP gRPC

Stack d’observabilitĂ© LLM recommandĂ©e

Pour une infrastructure on-premise souveraine, deux options :

OutilTypePoints fortsDéploiement
Langfuse (self-hosted)Traces + éval LLMInterface dédiée LLM, coûts par token, évaluation qualitéDocker Compose6
JaegerTraces distribuéesStandard CNCF, léger, intégré KubernetesDocker jaegertracing/all-in-one
Arize PhoenixTraces + debug agentSpécialisé agents/RAG, gratuit et open-sourcepip install arize-phoenix7

Stack minimale recommandée pour un agent custodien :

# docker-compose.yml — ajouter au stack existant
langfuse:
image: langfuse/langfuse:latest
ports:
- "3001:3000"
environment:
DATABASE_URL: "postgresql://langfuse:langfuse@postgres:5432/langfuse"
NEXTAUTH_SECRET: "votre-secret"
SALT: "votre-salt"
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
volumes:
- ./otel-config.yaml:/etc/otel-config.yaml
command: ["--config=/etc/otel-config.yaml"]
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP

Sauvegarde de l’état applicatif (DRP)

Le monitoring dĂ©tecte les pannes — mais sans sauvegarde, le redĂ©marrage aprĂšs incident peut prendre des heures ou perdre des donnĂ©es. Voici les Ă©tats Ă  protĂ©ger dans une stack d’infĂ©rence locale.

Ce qu’il faut sauvegarder

ComposantDonnées critiquesMéthode recommandée
Qdrant (base vectorielle)Collections + snapshots d’indexPOST /collections/{name}/snapshots → snapshot local ; copier vers stockage externe
Milvus (base vectorielle)Collections, segments, métadonnéesMilvus Backup CLI (milvus-backup create) vers S3 local ou NAS
SQLite (Memory Tree, historiques)Fichier .dbcp avec rotation quotidienne ou sqlite3 .backup en chaud
Configuration vLLM / Ollamaconfig.yaml, scripts de dĂ©marrageVersionnĂ© dans Git — dĂ©jĂ  couvert
ModÚles et adaptateursPoids GGUF, LoRA fine-tunésPoids de base = immuables (retélécharger) ; adaptateurs fine-tunés = sauvegarder sur NAS

Fréquences suggérées

Qdrant snapshot → quotidien (cron 02:00), conservation 7 jours
Milvus backup → quotidien (cron 03:00), conservation 7 jours
SQLite Memory Tree → toutes les heures (si Ă©criture frĂ©quente), sinon quotidien
Adaptateurs LoRA → à chaque fin d'entraünement

Exemple de snapshot Qdrant (curl)

FenĂȘtre de terminal
# Créer un snapshot
curl -X POST http://localhost:6333/collections/my_collection/snapshots
# Lister les snapshots disponibles
curl http://localhost:6333/collections/my_collection/snapshots
# Copier vers stockage externe (exemple NAS monté)
cp /qdrant/snapshots/my_collection/*.snapshot /mnt/backup/qdrant/

Procédure de reprise (RTO indicatif)

  1. RedĂ©marrer le conteneur vLLM ou Ollama → rechargement des poids depuis SSD (~15–120 s selon modĂšle)
  2. Restaurer Qdrant depuis le dernier snapshot → PUT /collections/{name}/snapshots/recover
  3. Restaurer SQLite → copier le fichier .db de sauvegarde à la place du fichier corrompu
  4. VĂ©rifier l’endpoint de santĂ© (/health ou /v1/models)

Voir aussi


Sources et Références

Footnotes

  1. vLLM Project, Production Metrics (endpoint /metrics, liste complĂšte des mĂ©triques Prometheus exposĂ©es, histogrammes de latence). https://docs.vllm.ai/en/stable/serving/metrics.html ↩ ↩2

  2. vLLM Project, Engine Arguments — gpu-memory-utilization (comportement swap KV Cache CPU, impact performances). https://docs.vllm.ai/en/stable/serving/engine_args.html ↩

  3. NVIDIA, DCGM Exporter — Metrics Reference (liste des mĂ©triques DCGM_FI_DEV_*, GPU utilization, memory, tempĂ©rature, NVLink). https://github.com/NVIDIA/dcgm-exporter ↩

  4. Grafana Labs, NVIDIA DCGM Exporter Dashboard (ID 12239, GPU metrics visualization). https://grafana.com/grafana/dashboards/12239 ↩

  5. Grafana Labs, Node Exporter Full Dashboard (ID 1860, system metrics — CPU, memory, disk, network). https://grafana.com/grafana/dashboards/1860 ↩

  6. Langfuse, Self-Hosting Guide & LiteLLM Integration (Docker Compose, OTEL ingestion, LLM observability). https://langfuse.com/docs/deployment/self-host ↩ ↩2

  7. Arize AI, Arize Phoenix — Open-source LLM Observability (traces agentiques, RAG debugging, OTEL-compatible). https://docs.arize.com/phoenix ↩ ↩2