Funk-lab/admin/incidents-llm-gpu.md
alkatrazz d7ee754e16 fix(litellm): request_timeout 600→60s + num_retries 2 (anti-connexion périmée)
Cause du burst de 502 « cold-start » : après un restart de llama-server, LiteLLM
garde des connexions keep-alive mortes dans son pool → la requête suivante hang
jusqu'au timeout. Or request_timeout valait 600s → hang jusqu'à 10 min, sans log
(LiteLLM attendait encore). Fix :
- request_timeout 60s : borne le hang d'une connexion morte
- num_retries 2 : rejoue → évince le socket périmé, repart sur une connexion neuve

Doc : section dédiée dans admin/incidents-llm-gpu.md (mécanisme + application +
reste à faire = watchdog qui bounce llama-server ET litellm).

Application : ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags litellm
(redémarre LiteLLM → applique le fix ET purge le pool d'un coup).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:58:24 +02:00

131 lines
6.4 KiB
Markdown

# Incidents LLM / GPU — llama-server (gpu-01)
Journal dédié des incidents d'**inférence** : `llama-server` (ROCm / RX 6700XT sur
gpu-01) et chaîne LLM `STT-server / Hermes → LiteLLM → llama-server`. Voir aussi
`incidents.md` (matériel & services storage-01/k8s) et `admin/ia/llama_server.md`.
---
## 2026-06-19 — llama-server gelé : `/health` OK mais inférence bloquée → 502 sur tout le LLM
### Symptômes
- STT (HUD, **composer texte**) : `502 Server Error: Bad Gateway for url: http://stt.lab.local/v1/ask`
- Petite **activité GPU** visible sur gpu-01 (le slot d'inférence tourne en rond)
- STT-server : `GET /healthz` → 200, mais `POST /v1/ask`**502**
- llama-server `:1234` : `/health``{"status":"ok"}` et `/v1/models``qwen3-8b` listé
**l'apparence est « up »**, ce qui masque la panne
- Mais une **génération réelle ne renvoie jamais rien** : `curl /v1/chat/completions`
hang (45 s sans un seul token)
- LiteLLM (storage-01) :
`litellm.Timeout: APITimeoutError - Request timed out. timeout value=600.0, time taken=600.0s.
Received Model Group=hermes-default` (après 2 retries)
### Cause
Le `llama-server` (gpu-01, `:1234`, `qwen3-8b`) était dans un état **wedgé** après
~2 jours d'uptime (démarré le 2026-06-17 21:04). Les endpoints de contrôle
(`/health`, `/v1/models`) répondaient encore, mais le **slot d'inférence ROCm était
bloqué** (vraisemblablement une requête avortée laissée dans le slot). Chaîne du 502 :
```
HUD composer → STT-server (/v1/ask) → LiteLLM :4000 (hermes-default) → llama-server gpu-01 :1234 ← GELÉ
```
LiteLLM attend `request_timeout = 600 s`, échoue, et le STT-server renvoie 502.
### Diagnostic (commandes utiles)
```bash
# 1) STT-server : confirmer que le 502 vient de lui (et pas de Traefik)
kubectl -n ai logs <pod stt-server> --tail=50 # → "POST /v1/ask HTTP/1.1" 502
# 2) LiteLLM : voir le timeout
ssh storage-01 'journalctl -u litellm -n 40 --no-pager --output=cat'
# → litellm.Timeout ... timeout value=600.0 ... Model Group=hermes-default
# 3) llama-server : /health MENT — tester une VRAIE génération
ssh gpu-01 'curl -s -m 30 http://127.0.0.1:1234/v1/chat/completions \
-H "Content-Type: application/json" \
-d "{\"model\":\"qwen3-8b\",\"messages\":[{\"role\":\"user\",\"content\":\"Dis bonjour. /no_think\"}],\"max_tokens\":30}"'
# gelé (aucune sortie) = wedgé | réponse JSON = sain
```
### Résolution
Redémarrer le service d'inférence sur gpu-01 :
```bash
ssh gpu-01 'sudo systemctl restart llama-server'
```
- L'ancienne instance gelée met **~40 s à mourir** (état `deactivating` le temps que
le slot bloqué se libère) — `systemctl restart` peut dépasser un timeout SSH court,
c'est normal ; vérifier avec `systemctl is-active llama-server` jusqu'à `active`.
- Au redémarrage, `/v1/chat/completions` renvoie `503 {"error":"Loading model"}`
pendant ~30 s (rechargement du modèle en VRAM) — **normal, attendre**.
- **Validation** : génération directe (`"Bonjour."` en ~80 ms) puis bout-en-bout
`POST http://stt.lab.local/v1/ask``{"reply":"Bonjour.","model":"hermes-default"}`.
### Observations / suites (hors présent incident)
- ⚠️ **Piège du health-check** : `/health` et `/v1/models` restent verts quand le
serveur est wedgé → un check qui ne fait **pas une vraie génération** ne voit pas la
panne (même angle mort que le crash-loop Qdrant en `activating`, cf. `incidents.md`).
- **Latence cerveau** : post-restart, 30-45 s pour une réponse triviale via STT-server
alors que le llama-server direct est à ~80 ms → le surcoût vient du pipeline du
cerveau (mémoire/embeddings Qdrant `stt-memory` + LiteLLM). À investiguer séparément.
- **Bruit LiteLLM** : `Invalid model name model=qwen3-1.7b-monitor` (profil monitor
Hermes) dans les logs — pré-existant, non lié à cet incident.
### Prévention (pistes)
- **Probe applicative** : sonde qui fait une vraie génération `/v1/chat/completions`
(pas seulement `/health`) → alerte si le LLM ne produit plus de tokens.
- **Watchdog** : si LiteLLM accumule des `Timeout` sur `hermes-default`, redémarrer
automatiquement `llama-server` sur gpu-01.
- Réduire le `request_timeout` LiteLLM (600 s est très long → un 502 tardif et opaque).
---
## 2026-06-19 (suite) — burst de 502 « cold-start » : connexions keep-alive périmées (LiteLLM)
### Symptôme
Après le déploiement du STT-server résilient (latence ramenée à ~340 ms en régime), un
**nouveau pod** STT (ou une reprise de trafic après inactivité) voyait ses **1-2 premières
requêtes hanger ~60 s puis 502**, ensuite tout repartait. Reproductible à chaque rollout.
### Cause
**Connexions keep-alive périmées dans le pool LiteLLM → llama-server.** Les redémarrages de
`llama-server` (cf. incident ci-dessus) tuent ses connexions, mais LiteLLM garde les
sockets morts dans son pool. La requête suivante part sur un socket mort → attend dans le
vide jusqu'au timeout. Or `litellm_settings.request_timeout` valait **600 s** → LiteLLM
pouvait hanger **10 min** sans rien logguer (d'où « LiteLLM ne logge aucune erreur » pendant
la fenêtre de 502 : il *attendait* encore). Le STT, lui, abandonne avant (timeout par
tentative) et renvoie 502.
> Diagnostic clé : llama-server **direct** est stable (10/10 à 0,32 s) ; le hang est dans la
> couche LiteLLM↔llama-server, pas dans llama-server ni le code STT.
### Correctifs
1. **Côté STT-server** (déployé, v0.2.1) : 2 tentatives avec fermeture du client httpx entre
les essais (connexion neuve) + timeout 30 s/tentative. Tolère un blip, mais ne couvre pas
un hang > 60 s.
2. **Côté LiteLLM** (`ansible/roles/litellm/templates/config.yaml.j2`) :
```yaml
litellm_settings:
request_timeout: 60 # était 600 — borne le hang d'une connexion morte
num_retries: 2 # rejoue → évince le socket périmé, repart sur une connexion neuve
```
Appliquer : `ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags litellm`
(⚠️ redémarre LiteLLM — service partagé Hermes/n8n/Open WebUI/Ghostfolio).
3. **Purge immédiate** (sans attendre l'IaC) : `sudo systemctl restart litellm` vide le pool.
### Reste à faire (cause racine)
Tant que `llama-server` se fige et nécessite des redémarrages, le pool LiteLLM se re-périme.
La vraie prévention = **watchdog de génération réelle** qui détecte le freeze et, idéalement,
bounce **à la fois** llama-server **et** litellm pour repartir sur des connexions saines.