Aller au contenu

vLLM : Maîtriser l'Inference Haute Performance pour les LLM

Mise à jour :

logo vllm

Les modèles de langage deviennent de plus en plus imposants et gourmands en ressources, vLLM (Virtual Large Language Model) représente une révolution dans le domaine de l’inférence. Développé par l’équipe de UC Berkeley, ce moteur d’inférence résout les principaux défis de performance rencontrés en production.

Les défis actuels des LLM en production :

  • Latence élevée : Les modèles prennent trop de temps à répondre
  • Utilisation mémoire excessive : Les GPU saturent rapidement
  • Faible débit : Peu de requêtes traitées simultanément
  • Coûts prohibitifs : Infrastructure surdimensionnée nécessaire

vLLM apporte des solutions concrètes à ces problématiques grâce à ses innovations techniques.

Qu’est-ce que vLLM ?

vLLM est une bibliothèque d’inférence haute performance développée par UC Berkeley. Elle révolutionne le serving de LLM grâce à PagedAttention, offrant jusqu’à 24x plus de débit que HuggingFace Transformers.

Voici les Avantages clés de vLLM :

  • Gestion optimisée de la mémoire avec PagedAttention
  • Traitement par lots (batch processing) intelligent
  • Compatibilité étendue avec les modèles les plus populaires
  • API compatible OpenAI pour l’utilisation dans vos ecosystèmes

Prérequis Techniques

En fonction du modèle que vous souhaitez déployer, les exigences matérielles peuvent varier. Cependant, voici quelques recommandations générales pour une installation optimale de vLLM pour des modèles de grande taille :

  • CPU : Processeur multi-cœurs récent (Intel Xeon ou AMD EPYC) avec 32 threads ou plus
  • GPU : Au moins une carte NVIDIA avec 32 Go de VRAM
  • RAM : Minimum 32 Go de RAM système
  • Stockage : SSD rapide avec au moins 500 Go d’espace libre
  • Système d’exploitation : Ubuntu 22.04 LTS

Pourquoi Utiliser autant de CPU/RAM ?

Les modèles de langage, en particulier ceux de grande taille, nécessitent une quantité significative de ressources CPU et RAM pour plusieurs raisons :

  • Traitement parallèle : Les modèles de langage exploitent le parallélisme pour accélérer l’inférence. Plus de cœurs CPU permettent de gérer plusieurs threads simultanément, réduisant ainsi la latence.
  • Gestion de la mémoire : Les modèles volumineux requièrent une gestion efficace de la mémoire pour stocker les poids du modèle et les données intermédiaires. Une RAM suffisante évite les goulots d’étranglement et les erreurs d’allocation mémoire.
  • Prétraitement et post-traitement : Les opérations de prétraitement des entrées et de post-traitement des sorties peuvent être intensives en CPU, surtout lorsqu’il s’agit de manipuler de grandes quantités de texte.
  • Support des charges de travail : Dans un environnement de production, plusieurs requêtes peuvent être traitées simultanément. Une configuration robuste en CPU et RAM garantit que le système peut gérer ces charges sans dégradation des performances.

Donc si vous prévoyez de déployer des modèles de langage de grande taille en production, il est crucial de disposer d’une infrastructure matérielle adéquate pour assurer des performances optimales et une expérience utilisateur fluide.

Installation et Configuration Avancée

Passons à la pratique avec une installation optimisée et une configuration avancée de vLLM. Je ne suis pas spécialiste mais j’ai essayé de compiler les meilleures pratiques issues de la documentation officielle et de la communauté.

  1. Vérification que les GPU sont bien des reconnus :
Terminal window
lspci | grep -i nvidia

Cette commande doit lister les GPU NVIDIA installés, par exemple :

Terminal window
13:00.0 3D controller: NVIDIA Corporation Device 2331 (rev a1)
14:00.0 3D controller: NVIDIA Corporation Device 2331 (rev a1)

On peut passer à l’installation.

  1. Mise à jour du système :

Commencer par mettre à jour le système :

Terminal window
sudo apt update && sudo apt upgrade -y
  1. Installation du kernel et des paquets essentiels :

Les GPU récents comme les H100 nécessitent une version de noyau ≥ 6.2.

Terminal window
sudo apt install -y linux-generic-hwe-22.04 linux-headers-generic-hwe-22.04
reboot

Vérifier la version du noyau après le redémarrage :

Terminal window
uname -r
6.8.0-79-generic # doit afficher 6.8.x ou plus

Installer les outils de base :

Terminal window
sudo apt install -y build-essential dkms wget curl git \
htop iotop sysstat numactl cpufrequtils irqbalance \
tuned ethtool net-tools python3-pip python3-venv python3-dev \
freeglut3-dev libx11-dev libxmu-dev libxi-dev \
libglu1-mesa-dev libfreeimage-dev libglfw3-dev
  1. Installation des Pilotes NVIDIA

Ajouter le dépôt CUDA :

Terminal window
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update

Installer drivers et CUDA :

Terminal window
sudo apt install -y cuda-drivers cuda-toolkit

Ajouter les chemins CUDA aux variables d’environnement.

Terminal window
# Retrait de toutes anciennes versions de CUDA dans le fichier .bashrc
sed -i '/^export PATH=\/usr\/local\/cuda/d' ~/.bashrc
# Détection automatique de la version CUDA installée
CUDA_PATH=$(find /usr/local -maxdepth 1 -name "cuda-*" -type d | sort -V | tail -1)
# Si pas de version spécifique trouvée, utiliser le lien symbolique
if [ -z "$CUDA_PATH" ]; then
CUDA_PATH="/usr/local/cuda"
fi
echo "Version CUDA détectée : $CUDA_PATH"
# Ajout des chemins aux variables d'environnement
echo "export PATH=$CUDA_PATH/bin:\$PATH" >> ~/.bashrc
echo "export LD_LIBRARY_PATH=$CUDA_PATH/lib64:\$LD_LIBRARY_PATH" >> ~/.bashrc
echo "export CUDA_HOME=$CUDA_PATH" >> ~/.bashrc
# Rechargement du profil
source ~/.bashrc
# On reboot pour s'assurer que tout est pris en compte
sudo reboot

Vérifier que vos GPU sont bien reconnus :

Terminal window
nvidia-smi

Cette commande doit afficher les GPU installés avec leurs détails, par exemple :

Terminal window
Wed Sep 17 12:55:57 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.82.07 Driver Version: 580.82.07 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA H100 PCIe On | 00000000:13:00.0 Off | 0 |
| N/A 37C P0 51W / 350W | 0MiB / 81559MiB | 0% Default |
| | | Disabled |
+-----------------------------------------+------------------------+----------------------+
| 1 NVIDIA H100 PCIe On | 00000000:14:00.0 Off | 0 |
| N/A 35C P0 49W / 350W | 0MiB / 81559MiB | 0% Default |
| | | Disabled |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+

Ici, on voit que 2× H100 sont correctement détectées.

Optimisations

Nous allons configurer les services pour optimiser les performances GPU. Toutes ces optimisations sont optionnelles, mais recommandées pour un usage en production.

  1. Activation du mode persistant :

Le mode persistant évite que les GPU ne se mettent en veille, ce qui peut introduire de la latence.

Terminal window
sudo systemctl enable --now nvidia-persistenced
  1. Paramétrage du scheduler CPU en mode performance :
Terminal window
echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils
sudo systemctl restart cpufrequtils
  1. Définition des Hugepages :

Les Hugepages améliorent la gestion de la mémoire pour les applications intensives comme vLLM.

Terminal window
echo 64 | sudo tee /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
echo 8192 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
  1. Tuned Profil :

Tuned ajuste automatiquement les paramètres système pour des performances optimales.

Terminal window
sudo tuned-adm profile latency-performance
tuned-adm active
sudo reboot # On reboot pour appliquer les changements

Installation de VLLM

Le plus dur est fait, on peut maintenant installer vLLM dans un environnement Python dédié.

  1. Commençons par créer un utilisateur dédié pour exécuter vLLM en production :
Terminal window
sudo adduser --disabled-password --gecos "" vllmuser
sudo usermod -aG sudo vllmuser
sudo su - vllmuser
  1. Création de l’environnement virtuel Python :
Terminal window
cd
python3 -m venv ~/venv
source ~/venv/bin/activate
  1. Installer les packages vLLM et ses dépendances :
Terminal window
pip install --upgrade pip setuptools wheel
pip install vllm mistral_common transformers tokenizers uvloop

Important : Création du répertoire cache Triton avec bonnes permissions :

Terminal window
# Création du cache Triton pour les kernels compilés
mkdir -p ~/.triton
chmod 755 ~/.triton
# Vérification que gcc est accessible
which gcc || echo "Erreur: gcc non trouvé"
  1. Vérification de l’installation :
Terminal window
python -c "import mistral_common; print(mistral_common.__version__)"
1.8.5 # doit afficher la version installée

Lancement de vLLM avec le model Mistral-Small-3.2-24B

Pour ce tutoriel, nous allons utiliser le modèle open-source Mistral-Small-3.2-24B-Instruct-2506, qui est un modèle de 24 milliards de paramètres optimisé pour les applications de type chat.

Attention, ce modèle nécessite environ 55 Go de VRAM pour fonctionner correctement. Avec nos 2× H100 de 80 Go, nous avons une marge confortable.

Terminal window
vllm serve mistralai/Mistral-Small-3.2-24B-Instruct-2506 \
--distributed-executor-backend mp \
--tensor-parallel-size 2 --pipeline-parallel-size 1 \
--dtype auto \
--tokenizer-mode mistral --config-format mistral --load-format mistral \
--tool-call-parser mistral \
--gpu-memory-utilization 0.92 \
--max-model-len 4096 \
--max-num-seqs 64 \
--max-num-batched-tokens 8192 \
--swap-space 16 \
--port 8000

Attention, le premier lancement peut prendre plusieurs minutes car les poids du modèle sont téléchargés depuis HuggingFace et mis en cache localement.

Explications des paramètres :

  • mistralai/Mistral-Small-3.2-24B-Instruct-2506 Modèle 24 milliards de paramètres optimisé pour l’instruction-following.
  • --distributed-executor-backend mp Utilise le backend multiprocessing pour répartir les tâches.
  • --tensor-parallel-size 2 Découpe les poids du modèle sur 2 GPU (utile avec tes 2× H100).
  • --pipeline-parallel-size 1 Pas de découpage supplémentaire des couches → tout passe en tensor parallelism.
  • --dtype auto Choisit automatiquement le type de calcul adapté (bf16 sur H100).
  • --tokenizer-mode mistral Active le tokenizer officiel de Mistral.
  • --config-format mistral / --load-format mistral Indique que la config et les poids suivent le format Mistral.
  • --tool-call-parser mistral Active le parser de tool calls propre à Mistral.
  • --gpu-memory-utilization 0.92 Autorise vLLM à utiliser 92 % de la VRAM du GPU (évite les OOM).
  • --swap-space 16 Active un swap CPU de 16 Go en cas de dépassement mémoire GPU.
  • --max-model-len 4096 Contexte maximum : 4096 tokens (~3 000 mots).
  • --max-num-seqs 64 Nombre maximum de séquences simultanées dans un batch.
  • --max-num-batched-tokens 8192 Nombre total de tokens par batch. → Cela équilibre latence et débit (throughput).
  • --port 8000 Le serveur écoute sur http://localhost:8000 avec une API compatible OpenAI.

Quelques recommandations pour ajuster les paramètres de batching selon tes besoins :

Si tu veux plus des contextes plus longs, essaie par paliers :

  • --max-model-len 8192 avec --max-num-seqs 64, --max-num-batched-tokens 8192
  • --max-model-len 16384 avec --max-num-seqs 48, --max-num-batched-tokens 8192
  • --max-model-len 32768 avec --max-num-seqs 24–32, --max-num-batched-tokens 4096–8192

Si tu veux max de débit :

Garde --max-model-len 4096–8192, pousse --max-num-seqs et --max-num-batched-tokens tant que la VRAM tient et que la latence reste acceptable. Nous allons voir ça dans la section benchmarks.

Création d’un service systemd

Afin de faciliter le démarrage automatique de vLLM au boot du serveur, on va créer un service systemd. Mais le plus compliqué sera de le démarrer au bon moment, une fois que les GPU seront initialisés et prêts.

Voici un exemple de fichier de service systemd pour vLLM :

[Unit]
Description=vLLM Service
After=network-online.target nvidia-persistenced.service
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=3
[Service]
Type=simple
User=vllmuser
Group=vllmuser
WorkingDirectory=/home/vllmuser
Environment="PATH=/home/vllmuser/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
Environment="LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/lib/x86_64-linux-gnu"
Environment="CUDA_HOME=/usr/local/cuda"
Environment="HF_HUB_OFFLINE=0"
Environment="HF_HUB_CACHE=/home/vllmuser/.cache/huggingface"
Environment="CUDA_VISIBLE_DEVICES=0,1"
Environment="NO_COLOR=1"
Environment="FORCE_COLOR=0"
ExecStart=/home/vllmuser/venv/bin/vllm serve mistralai/Mistral-Small-3.2-24B-Instruct-2506 \
--distributed-executor-backend mp \
--tensor-parallel-size 2 --pipeline-parallel-size 1 \
--dtype auto \
--tokenizer-mode mistral --config-format mistral --load-format mistral \
--tool-call-parser mistral \
--gpu-memory-utilization 0.92 \
--max-model-len 4096 \
--max-num-seqs 64 \
--max-num-batched-tokens 8192 \
--swap-space 16 \
--port 8000 \
--host 0.0.0.0 \
--download-dir /home/vllmuser/.cache/huggingface
TimeoutStartSec=1800
Restart=on-failure
RestartSec=30
KillMode=mixed
KillSignal=SIGTERM
StandardOutput=append:/var/log/vllm/vllm.log
StandardError=append:/var/log/vllm/vllm-error.log
SyslogIdentifier=vllm
# (Optionnel) des limites plus larges suivant ta charge
# LimitNOFILE=1048576
# TasksMax=infinity
[Install]
WantedBy=multi-user.target
  1. Sauvegarde ce fichier sous /etc/systemd/system/vllm.service.
  2. Remplace vllmuser par le nom de l’utilisateur qui exécute vLLM.
  3. Recharge les services systemd :
Terminal window
sudo systemctl daemon-reload
  1. Préparation des répertoires de logs :

Avant d’activer le service, créez les répertoires et fichiers de logs avec les bonnes permissions :

Terminal window
# Création du répertoire de logs
sudo mkdir -p /var/log/vllm
# Création des fichiers de logs
sudo touch /var/log/vllm/vllm.log
sudo touch /var/log/vllm/vllm-error.log
# Attribution des permissions à l'utilisateur vllmuser
sudo chown -R vllmuser:vllmuser /var/log/vllm
sudo chmod 755 /var/log/vllm
sudo chmod 644 /var/log/vllm/*.log
  1. Configuration de la rotation des logs :

Pour éviter que les logs ne prennent trop d’espace disque, configurez logrotate :

Terminal window
sudo tee /etc/logrotate.d/vllm << 'EOF'
/var/log/vllm/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
copytruncate
su vllmuser vllmuser
}
EOF
  1. Active le service pour qu’il démarre au boot :
Terminal window
sudo systemctl enable --now vllm.service
  1. Vérifie le statut du service :
Terminal window
sudo systemctl status vllm.service

Il doit indiquer que le service est actif (running). Si ce n’est pas le cas, consulte les logs avec :

Terminal window
sudo journalctl -u vllm.service -f

Benchmarks de contrôle des performances

Mettre en production un modèle comme Mistral-Small-3.2-24B ne consiste pas seulement à le faire tourner. Il est indispensable de mesurer ses performances pour vérifier qu’il répond à tes besoins en termes de latence, de débit (throughput) et de stabilité sous charge.

Pourquoi faire des benchmarks ?

Les benchmarks permettent de répondre à plusieurs questions clés :

  • Quelle est la latence moyenne d’une réponse ?
  • Combien de requêtes simultanées mon serveur peut-il gérer ?
  • Quelle est la consommation des ressources GPU/CPU pendant l’inférence ?
  • Quels paramètres de vLLM (--max-model-len, --max-num-seqs, --max-num-batched-tokens) offrent le meilleur compromis entre latence et débit ?

Sans ces mesures, il est impossible d’optimiser ton infrastructure et d’anticiper les coûts.

Mais la question que je me pose est : quel est le niveau de performance attendu en fonction des ressources à disposition (2× H100, 4× A100, etc.) et des paramètres choisis ?

Un moyen simple de mesurer la latence est d’utiliser un script Python qui envoie une requête à l’API vLLM :

import json, time, httpx
URL = "http://localhost:8000/v1/chat/completions"
payload = {
"model": "mistralai/Mistral-Small-3.2-24B-Instruct-2506",
"messages": [{"role":"user","content":"Explique le RAG en 3 points"}],
"stream": True,
"tool_choice":"none",
"temperature": 0,
"top_p": 1,
"max_tokens": 128
}
with httpx.Client(timeout=120.0) as client:
t0 = time.perf_counter()
ttft = None
tokens = 0
with client.stream("POST", URL, json=payload) as r:
r.raise_for_status()
for line in r.iter_lines():
if not line or not line.startswith("data:"):
continue
data = line[5:].strip()
if data == "[DONE]":
break
obj = json.loads(data)
delta = obj["choices"][0].get("delta", {}).get("content")
if delta:
tokens += len(delta.split())
if ttft is None:
ttft = time.perf_counter() - t0
total = time.perf_counter() - t0
print(f"TTFT: {ttft:.3f}s | total: {total:.3f}s | tokens: {tokens} | decode rate: {tokens/(total-ttft):.1f} tok/s")

Ce script calcule :

  • la latence totale d’une requête,
  • le nombre de tokens générés,
  • le débit en tokens par seconde.

En fonction des résultats, ajuste les paramètres suivants :

  • Pour augmenter le contexte : élève --max-model-len (8192, 16384…), mais réduis --max-num-seqs pour éviter l’OOM.
  • Pour maximiser le débit : garde --max-model-len bas (4096–8192), et augmente --max-num-seqs / --max-num-batched-tokens.
  • Pour réduire la latence : diminue --max-num-seqs afin que les batchs partent plus vite.

Conclusion

Avec vLLM, il est possible de déployer des modèles de langage de grande taille en production avec des performances optimales. En suivant les bonnes pratiques d’installation, de configuration et de benchmarking, tu peux t’assurer que ton infrastructure est prête à répondre aux exigences de tes applications.

N’hésite pas à expérimenter avec différents modèles et paramètres pour trouver la configuration qui convient le mieux à tes besoins spécifiques.

Plus d’infos