Aperta Scientia Crest
← Retour au Tech Radar
📡 Aperta Intelligence Lab
Autoscaling Intelligent des LLM avec KEDA et vLLM sur OpenShift : Scaler sur le KV-Cache et la Latence ITL

Autoscaling Intelligent des LLM avec KEDA et vLLM sur OpenShift : Scaler sur le KV-Cache et la Latence ITL

📅 14 septembre 2026
Tech Radar AI Infrastructure Kubernetes & OpenShift LLMOps

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é :

  1. 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.
  2. 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 de 0.0 à 1.0).
  3. 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_waiting dépasse 2 requêtes en attente.
  • Si le vllm:gpu_cache_usage_factor moyen 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 :

  1. De l’allocation dynamique du nœud GPU via le MachineSet OpenShift / Cluster Autoscaler.
  2. Du téléchargement des poids du modèle (10 à 70 Go) depuis le stockage objet S3/Ceph.
  3. 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 cooldownPeriod d’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’AutoscalingHPA Standard (CPU / RAM)HPA Custom (GPU Memory Util)KEDA + Métriques vLLM (KV-Cache & Waiting)
Précision du SignalNulle (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 BurstsTrès lenteInefficaceInstantanée (déclenchement dès requests_waiting > 2)
Gestion des Prompts LongsAveugleAveugleNative (mesure directe de l’occupation du KV-Cache)
Optimisation des Coûts GPUFaible (risque de crash)Faible (sur-provisionnement permanent)Optimale (scale-in contrôlé et scale-out chirurgical)
Intégration OpenShiftBasiqueNécessite NVIDIA GPU OperatorComplè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 :

  1. Exposez systématiquement les métriques vLLM : Vérifiez que le flag --disable-log-stats n’est pas activé et que le port de métriques est accessible par votre ServiceMonitor.
  2. 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.
  3. 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.
  4. Automatisez le déploiement via GitOps (ArgoCD) : Déclarez vos ScaledObject et ServiceMonitor dans 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).

Découvrir les cursus →