Autoscaling Intelligent des LLM avec KEDA et vLLM sur OpenShift : Scaler sur le KV-Cache et la Latence ITL
Sommaire de l'analyse
Dans les déploiements de modèles de langage (LLMs) en production, l’autoscaling d’infrastructure représente un paradoxe économique et opérationnel majeur : D’un côté, le sur-provisionnement de nœuds GPU (NVIDIA H100/H200, B200 ou L40S) génère des coûts d’infrastructure exorbitants pendant les heures creuses. De l’autre, un sous-dimensionnement entraîne une explosion de la file d’attente de requêtes, une saturation de la mémoire et des dégradations inacceptables du Time-To-First-Token (TTFT) et de l’Inter-Token Latency (ITL) pour les utilisateurs et agents IA.
Le réflexe classique des équipes d’infrastructure consiste à déployer un Horizontal Pod Autoscaler (HPA) Kubernetes basé sur l’utilisation CPU, mémoire RAM ou l’allocation GPU standard. Or, sur les moteurs d’inférence modernes comme vLLM ou TGI, cette approche est inefficace : la mémoire VRAM est préallouée à 90 % dès l’initialisation du moteur par PagedAttention, rendant les métriques d’allocation mémoire plates et aveugles.
Découvrez comment mettre en œuvre un autoscaling événementiel intelligent avec KEDA (Kubernetes Event-driven Autoscaling) et Red Hat OpenShift AI (RHOAI), en pilotant le cycle de vie des réplicas d’inférence directement à partir de la pression du KV-Cache et de la file d’attente vLLM.
1. Pourquoi l’Autoscaling Traditionnel Échoue sur les LLM
Pour comprendre l’échec des mécanismes d’autoscaling traditionnels sur les charges de travail GenAI, il faut analyser le comportement interne du moteur vLLM :
┌─────────────────────────────────────────────────────────────────────────────┐
│ Pourquoi l'HPA Standard est Aveugle │
├─────────────────────────────────────────────────────────────────────────────┤
│ 1. Mémoire VRAM : vLLM préalloue le KV-Cache au boot (ex. gpu_memory_utilization=0.90). │
│ => Métrique VRAM perçue par Kubernetes : 90 % en permanence (aucun signal de charge). │
│ │
│ 2. GPU Utilization (%) : Fluctue violemment entre les phases de Prefill et Decode. │
│ => Crée du "flapping" (oscillations rapides et destructrices de pods). │
│ │
│ 3. Trafic Réseau HTTP (RPS) : Toutes les requêtes ne se valent pas ! │
│ => Un prompt de 4000 tokens sature le KV-Cache 20x plus qu'un prompt court. │
└─────────────────────────────────────────────────────────────────────────────┘
Pour déclencher un scaling prédictif et fluide, Kubernetes doit surveiller l’état interne de la boucle de batching continu (Continuous Batching) via les métriques exposées par l’endpoint /metrics de vLLM.
2. Les Métriques Clés de vLLM pour l’Autoscaling
vLLM expose nativement au format Prometheus des indicateurs de performance haute fidélité. Trois métriques constituent les piliers du scaling automatisé :
vllm:num_requests_waiting: Le nombre de requêtes en attente dans la file d’ordonnancement interne de vLLM, faute de blocs KV-Cache disponibles. Tout chiffre supérieur à 0 indique une saturation immédiate.vllm:gpu_cache_usage_factor: Le ratio de blocs mémoire du KV-Cache actuellement réservés pour les séquences en cours de décodage (valeur de0.0à1.0).vllm:time_to_first_token_seconds_bucket/vllm:time_per_output_token_seconds: La latence effective subie par les clients, idéale pour déclencher des alertes de dégradation SLA.
┌─────────────────────────────────────────────────────────┐
│ Trafic Ingress (Requêtes LLM / Prompts Entrants) │
└────────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ OpenShift AI / KServe InferenceService (vLLM) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Metrics Exporter: /metrics │ │
│ │ • vllm:gpu_cache_usage_factor │ │
│ │ • vllm:num_requests_waiting │ │
│ └────────────────────────┬────────────────────────┘ │
└────────────────────────────┼────────────────────────────┘
│ Scrape (10s)
▼
┌─────────────────────────────────────────────────────────┐
│ OpenShift User-Workload Monitoring │
│ (Prometheus / Thanos) │
└────────────────────────────┬────────────────────────────┘
│ Query PromQL
▼
┌─────────────────────────────────────────────────────────┐
│ KEDA Autoscaling Operator │
│ (ScaledObject: évalue seuil cache > 0.85 ou wait > 2) │
└────────────────────────────┬────────────────────────────┘
│ Scale Out / Scale In
▼
┌─────────────────────────────────────────────────────────┐
│ Orchestrateur GPU OpenShift (DRA / Node AutoScaler)│
│ Allocation de nouveaux Pods vLLM sur nœuds GPU │
└─────────────────────────────────────────────────────────┘
3. Architecture Déclarative : Configuration KEDA & ScaledObject
Sur OpenShift, KEDA s’installe en un clic via l’OperatorHub. Il s’appuie sur le composant OpenShift User-Workload Monitoring pour interroger les métriques Prometheus sans surcharger les pods d’inférence.
Étape 1 : Activer le ServiceMonitor pour vLLM
Ce manifeste indique à Prometheus de collecter les métriques du runtime vLLM toutes les 10 secondes :
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: vllm-metrics-monitor
namespace: ai-inference-prod
labels:
app.kubernetes.io/name: vllm-granite-3b
spec:
selector:
matchLabels:
serving.kserve.io/inferenceservice: granite-3b-instruct
endpoints:
- port: metrics
path: /metrics
interval: 10s
scrapeTimeout: 5s
Étape 2 : Définir l’Authentification KEDA avec Thanos Querier
Pour sécuriser l’accès de KEDA à l’API de métriques interne d’OpenShift :
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: keda-trigger-auth-prometheus
namespace: ai-inference-prod
spec:
secretTargetRef:
- parameter: bearerToken
name: thanos-querier-token
key: token
- parameter: ca
name: thanos-querier-ca
key: ca.crt
Étape 3 : Déployer le ScaledObject KEDA Multi-Critères
Le ScaledObject suivant ajuste le nombre de réplicas vLLM entre 1 et 8 pods selon deux règles combinées :
- Si
vllm:num_requests_waitingdépasse 2 requêtes en attente. - Si le
vllm:gpu_cache_usage_factormoyen dépasse 0.80 (80 % du KV-Cache alloué).
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: vllm-granite-scaledobject
namespace: ai-inference-prod
spec:
scaleTargetRef:
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
name: granite-3b-instruct
minReplicaCount: 1
maxReplicaCount: 8
cooldownPeriod: 300 # Évite le scale-in trop rapide (cooldown de 5 min)
pollingInterval: 15 # Fréquence d'évaluation
advanced:
horizontalPodAutoscalerConfig:
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60
triggers:
- type: prometheus
metadata:
serverAddress: https://thanos-querier.openshift-monitoring.svc.cluster.local:9091
metricName: vllm_waiting_requests_trigger
threshold: '2'
query: sum(vllm:num_requests_waiting{namespace="ai-inference-prod", model_name="granite-3b-instruct"})
authModes: bearer
authenticationRef:
name: keda-trigger-auth-prometheus
- type: prometheus
metadata:
serverAddress: https://thanos-querier.openshift-monitoring.svc.cluster.local:9091
metricName: vllm_kv_cache_pressure_trigger
threshold: '0.80'
query: avg(vllm:gpu_cache_usage_factor{namespace="ai-inference-prod", model_name="granite-3b-instruct"})
authModes: bearer
authenticationRef:
name: keda-trigger-auth-prometheus
4. Gérer le Défi du “Cold Start” GPU sur OpenShift
Si KEDA permet de déclencher l’instanciation de nouveaux pods en quelques millisecondes, le temps de démarrage effectif d’un pod vLLM (Cold Start) peut atteindre 45 à 120 secondes en raison :
- De l’allocation dynamique du nœud GPU via le MachineSet OpenShift / Cluster Autoscaler.
- Du téléchargement des poids du modèle (10 à 70 Go) depuis le stockage objet S3/Ceph.
- De l’initialisation des kernels CUDA et du graphe d’exécution PyTorch.
Bonnes Pratiques d’Ingénierie pour Réduire le Cold Start :
- Shared Model Cache via ReadWriteMany (CephFS / Lustre / ODF) : Montez un cache local en lecture partagée (
PVC ReadWriteMany) pour que les nouveaux pods accèdent instantanément aux poids sans téléchargement réseau. - Warm Pool & Pre-warmed Nodes : Conservez au moins un réplica actif (
minReplicaCount: 1) et des nœuds GPU prêts à l’emploi avec les images de conteneurs pré-téléchargées (cached images). - Politique de Scale-In Conservatrice : Utilisez un
cooldownPeriodd’au moins 300 secondes (5 minutes) pour empêcher de détruire des pods GPU qui ont mis du temps à chauffer alors qu’une nouvelle rafale de trafic peut survenir.
5. Comparatif des Stratégies d’Autoscaling pour les LLM
| Critère d’Autoscaling | HPA Standard (CPU / RAM) | HPA Custom (GPU Memory Util) | KEDA + Métriques vLLM (KV-Cache & Waiting) |
|---|---|---|---|
| Précision du Signal | Nulle (non corrélée à l’inférence) | Trompeuse (VRAM préallouée à 90%) | Maximale (pression réelle de calcul & file d’attente) |
| Réactivité face aux Bursts | Très lente | Inefficace | Instantanée (déclenchement dès requests_waiting > 2) |
| Gestion des Prompts Longs | Aveugle | Aveugle | Native (mesure directe de l’occupation du KV-Cache) |
| Optimisation des Coûts GPU | Faible (risque de crash) | Faible (sur-provisionnement permanent) | Optimale (scale-in contrôlé et scale-out chirurgical) |
| Intégration OpenShift | Basique | Nécessite NVIDIA GPU Operator | Complète via KEDA Operator + OpenShift Monitoring |
6. Guide d’Implémentation pour les Équipes Plateforme & LLMOps
Pour industrialiser l’autoscaling de vos clusters d’inférence en production :
- Exposez systématiquement les métriques vLLM : Vérifiez que le flag
--disable-log-statsn’est pas activé et que le port de métriques est accessible par votre ServiceMonitor. - Combinez toujours deux déclencheurs : Utilisez conjointement la pression de cache (
gpu_cache_usage_factor) pour absorber les prompts volumineux et la file d’attente (num_requests_waiting) pour les rafales d’utilisateurs simultanés. - Paramétrez des alertes sur le temps de réponse (TTFT) : Si la latence médiane au premier token dépasse 800 ms, ajustez les seuils de déclenchement du ScaledObject pour être plus agressif sur le scale-out.
- Automatisez le déploiement via GitOps (ArgoCD) : Déclarez vos
ScaledObjectetServiceMonitordans vos dépôts d’infrastructure pour un versioning rigoureux.
Maîtrisez l’Ingénierie des Systèmes d’Inférence IA avec Aperta Scientia
La mise en production de modèles de fondation à grande échelle exige une double expertise : la maîtrise de l’orchestration Cloud-Native Kubernetes et l’optimisation fine des moteurs d’inférence GenAI.
Aperta Scientia prépare vos ingénieurs aux architectures d’IA les plus exigeantes :
- AS300 — AI Platform Engineer : Le cursus d’élite de 3 mois pour maîtriser le déploiement d’OpenShift AI (RHOAI), l’optimisation des moteurs vLLM, l’autoscaling avec KEDA, le serving déclaratif avec KServe, les bases vectorielles Milvus, et la gouvernance avec TrustyAI.
- AS200 — New DevOps Platform Engineer : Le cursus fondamental pour concevoir des clusters Red Hat OpenShift résilients, automatiser en GitOps (ArgoCD), configurer l’observabilité Prometheus / Thanos, et orchestrer le multi-cluster avec RHACM.
Appliquer ces technologies en production
Découvrez nos cursus intensifs de 3 mois AS200 (DevOps) et AS300 (AI Platform Engineer).