NVMe ou SSD sur un VPS : quelle différence ?
Le NVMe réduit la latence et augmente les IOPS, mais l’hyperviseur et vos voisins limitent les gains. Testez votre VPS avec fio pour mesurer ses performances.
Le NVMe a-t-il de l’importance sur un VPS ?
Le NVMe a de l’importance sur un VPS lorsque vos logiciels effectuent de nombreuses petites opérations de lecture et d’écriture et attendent la fin de chacune d’elles. Il apporte peu à un site qui sert des pages mises en cache ou à un programme qui passe son temps à attendre le réseau. Le support de stockage n’est qu’un facteur. L’hyperviseur situé devant le disque et les autres instances qui partagent le même hôte déterminent les performances maximales que vous obtenez réellement.
Ce que NVMe change et ce qu’il ne change pas
NVMe (non-volatile memory express) n’est pas un type de mémoire flash. Il s’agit du protocole et de la connexion utilisés pour accéder à la mémoire flash. Un périphérique NVMe utilise des lignes PCIe (peripheral component interconnect express) et communique avec le protocole NVMe. Un SSD SATA (serial ATA) utilise une liaison SATA et communique avec AHCI (advanced host controller interface). Les puces mémoire qui stockent vos octets peuvent être identiques dans les deux cas.
Deux éléments diffèrent. Dans les deux cas, la différence concerne le chemin des commandes, et non le stockage lui-même.
Files d’attente. AHCI fournit au noyau une seule file d’attente de commandes pouvant contenir 32 commandes. NVMe autorise des milliers de files d’attente, en pratique une par cœur CPU, chacune étant bien plus profonde que 32. Un seul processus qui lit un bloc à la fois ne verra pas la différence. Une base de données qui effectue 64 lectures simultanément, oui : en SATA, la 33e requête attend une place dans la file avant même que le périphérique ne la voie, tandis que le périphérique NVMe les accepte toutes et les traite en parallèle.
Largeur de liaison. Une liaison SATA III fonctionne à 6 Gbit/s, soit environ 550 MB/s de données réelles après la surcharge du protocole. Il s’agit d’une limite fixe, quelle que soit la mémoire flash située derrière. Quatre lignes PCIe transportent plusieurs gigaoctets par seconde. La liaison cesse donc d’être le facteur limitant.
Les attentes sont généralement erronées concernant la latence. Avec une profondeur de file de 1, c’est-à-dire une seule requête en cours, un SSD SATA répond à une lecture 4k en environ 100 à 150 microsecondes. NVMe répond en environ 80 à 100 microsecondes. Les deux sont rapides. Aucun logiciel que vous exécutez ne remarquera la différence sur une seule requête. L’écart apparaît avec la concurrence. La profondeur de file, c’est-à-dire le nombre de requêtes en cours simultanément, détermine si les deux supports semblent identiques ou très différents.
Le stockage par blocs sur le réseau constitue une troisième catégorie, avec des caractéristiques différentes. Une écriture traverse le réseau jusqu’à un cluster de stockage et n’est acquittée que lorsque le cluster la contient. Sa latence se mesure donc en millisecondes plutôt qu’en microsecondes. En contrepartie, vous obtenez de la durabilité : le volume survit à l’hôte auquel il est attaché, et vous pouvez créer des snapshots et le redimensionner.
Chiffres généralement publiés : NVMe, SSD SATA et stockage réseau
The data behind this chart
[
{
"disk": "Local NVMe SSD",
"iops_4k_read": "184,000",
"p99_latency_ms": 0.4,
"seq_read_mbps": "3,400"
},
{
"disk": "Local SATA SSD",
"iops_4k_read": "90,000",
"p99_latency_ms": 1.2,
"seq_read_mbps": "550"
},
{
"disk": "Network block storage",
"iops_4k_read": "12,500",
"p99_latency_ms": 6.5,
"seq_read_mbps": "250"
}
]Un périphérique NVMe local est généralement annoncé à 184,000 IOPS de lecture aléatoire en 4k (opérations d’entrée/sortie par seconde), avec une profondeur de file d’attente de 32. Le même test sur un SSD SATA est annoncé autour de 90,000, limité par l’unique file d’attente AHCI et la liaison à 6 Gbit/s. Le stockage par blocs sur le réseau est généralement plafonné par le fournisseur plutôt que par le matériel, et 12,500 constitue une limite documentée courante.
La latence exprime le même écart dans l’unité que vos utilisateurs ressentent. La latence de lecture p99, c’est-à-dire celle des 1 % de requêtes les plus lentes, est d’environ 0.4 ms sur un NVMe local et de 1.2 ms sur SATA. Si le réseau se trouve sur le chemin, elle atteint 6.5 ms, soit plus de dix fois la valeur du NVMe.
Les lectures séquentielles présentent l’écart le plus important, mais aussi le moins utile : 3,400 Mo/s contre 550 Mo/s. Presque aucun service sur un serveur ne lit un fichier volumineux de bout en bout à pleine vitesse. Les colonnes des accès aléatoires et de la latence décrivent ce que font réellement une base de données, une file d’attente de messagerie ou un gestionnaire de paquets.
D’où viennent ces chiffres et pourquoi les vôtres seront différents
Les 3 lignes reprennent les chiffres des fiches techniques des fournisseurs pour les périphériques locaux et les limites documentées par volume pour le stockage réseau, valables en juillet 2026 et arrondies. Elles supposent une taille de bloc de 4k, des lectures aléatoires, une profondeur de file d’attente de 32 et un seul job, ce qui correspond au type de test publié par un fournisseur. Votre VPS est un guest sur un hôte partagé. Le même test renvoie donc généralement une valeur inférieure sur votre machine, qui varie également d’une exécution à l’autre. Considérez ces lignes comme une indication de l’écart entre les trois catégories, et non comme un objectif à atteindre.
Quelles charges de travail sont sensibles au disque
Une seule règle permet de toutes les comprendre : une charge de travail ne remarque le disque que lorsqu’elle attend le disque. Linux conserve les données des fichiers récemment utilisées en RAM, dans le page cache. La deuxième lecture d’un fichier n’atteint donc jamais le stockage. Si le working set, c’est-à-dire les données réellement utilisées, tient en RAM, les lectures deviennent des lectures mémoire après le premier passage. Les écritures sont différentes. Toute écriture que l’application force avec fsync() doit être présente sur un stockage stable avant que l’application puisse continuer.
Travail qui valide les transactions. PostgreSQL, MySQL et SQLite appellent fsync() ou fdatasync() lors de la validation, et chaque validation attend la réponse du périphérique. Le taux de validation d’une connexion dépend donc de la latence d’écriture, et non de la bande passante. Un périphérique qui effectue un flush en 0.2 ms autorise beaucoup plus de validations par seconde qu’un périphérique qui met 5 ms. Aucun niveau de débit ne change ce résultat. MySQL l’indique dans l’error log lorsque le flush ne suit plus :
[Note] InnoDB: page_cleaner: 1000ms intended loop took 4589ms. The settings might not be optimal.PostgreSQL le signale dans ses lignes de checkpoint. Une valeur sync= élevée signifie que le flush lui-même était lent :
LOG: checkpoint complete: wrote 8192 buffers (25.0%); write=27.694 s, sync=11.207 s, total=39.001 sTravail qui manipule de nombreux petits fichiers. Chaque fichier entraîne des opérations sur les métadonnées, contrairement à une seule grande lecture séquentielle. npm install, git clone d’un grand dépôt, le déballage d’images de conteneurs, un magasin de messages Maildir et une sauvegarde qui parcourt une arborescence volumineuse passent tous leur temps sur des accès aléatoires de petite taille. Une tâche de sauvegarde restic sur un VPS lit et calcule le hash de chaque fichier qu’elle n’a pas encore rencontré. Le temps réel d’une sauvegarde portant sur un million de fichiers suit donc étroitement la latence de lecture aléatoire. Il en va de même pour du -sh, qui ne lit que les métadonnées.
Les bases de données qui dépassent la capacité de la RAM appartiennent également à cette catégorie. Dès que l’index ne tient plus dans le page cache, chaque recherche devient une lecture aléatoire et le disque revient dans le chemin critique.
Quelles charges de travail ne sont pas affectées par le disque
Un blog ou un petit site d’entreprise. Les pages sont légères, le cache de pages les conserve toutes après la première requête, et la limite vient du CPU pour le rendu ou de la bande passante pour les ressources. Une stack LAMP sur Ubuntu 24.04 qui sert un site à faible trafic ne génère pratiquement plus d’E/S disque une fois le cache rempli.
Le streaming multimédia. Un flux 4K à 40 Mbit/s lit 5 MB/s. Dix flux lisent 50 MB/s, ce que même un stockage en mode bloc sur le réseau peut fournir sans difficulté. Un serveur multimédia Jellyfin sur un VPS est limité par le débit sortant autorisé sur le réseau et par le CPU lorsqu’il transcode, pas par le support de stockage.
L’inférence avec un modèle local. Exécuter Ollama sur un VPS pour auto-héberger un LLM lit le fichier du modèle une fois, puis travaille en RAM. Le NVMe réduit le temps de chargement d’un modèle de 20 GB, qui passe de plusieurs minutes à quelques secondes. Il ne modifie pas le nombre de tokens par seconde, qui dépend de la bande passante mémoire et du CPU.
Toute charge qui attend un service externe. Un worker qui passe 800 ms par tâche à effectuer une requête HTTP ne sera pas plus rapide avec un disque plus performant.
Pourquoi l’hyperviseur compte autant que le support
Vous ne communiquez jamais directement avec le support de stockage. Vous utilisez un disque virtuel présenté par l’hyperviseur, généralement via virtio. Plusieurs décisions prises à ce niveau comptent davantage que le choix entre NVMe et SATA.
Vous ne pouvez pas voir le support depuis le guest. lsblk -d -o NAME,ROTA,SIZE,MODEL affiche vda avec un modèle vide, car virtio ne transmet pas l’identité du disque. cat /sys/block/vda/queue/rotational indique ce que l’hyperviseur annonce. Une valeur de 0 ne prouve donc pas la présence de flash. nvme list, fourni par le package nvme-cli, ne liste généralement aucun périphérique sur les VPS, même lorsque l’hôte utilise des disques NVMe. Votre disque est un périphérique virtio, pas un périphérique NVMe. Une offre qui mentionne NVMe décrit généralement le stockage de l’hôte. Votre volume peut tout de même être rattaché au réseau.
Le mode de cache de l’hôte modifie davantage les résultats que le support. Avec la mise en cache writeback sur l’hôte, un guest fsync() peut répondre dès que l’hôte a les données dans sa propre RAM. Le benchmark produit alors un résultat qu’aucun périphérique physique ne pourrait atteindre. Un crash de l’hôte peut également entraîner la perte d’écritures que votre base de données considère comme sûres. Avec le mode de cache none, les résultats sont plus faibles et représentatifs.
Limites et crédits de burst. De nombreux fournisseurs limitent les IOPS par volume ou selon l’offre. De nombreux volumes réseau utilisent également une réserve de burst. Cette réserve fonctionne comme un pool de crédits : le volume reste rapide tant que les crédits sont disponibles, puis revient à un niveau de performance beaucoup plus faible. Le symptôme est facile à reconnaître. Une importation ou une restauration s’exécute rapidement pendant plusieurs minutes, puis ralentit fortement et reste lente, sans aucune modification de votre configuration. Vous avez consommé les crédits.
Voisins. Sur un hôte partagé, la latence de votre disque varie selon l’activité des autres guests. C’est pourquoi vous devez effectuer plusieurs mesures. Exécutez le même test le matin, puis le soir, et comparez l’écart entre les résultats. Sur un hôte chargé, la différence entre deux exécutions sur le même volume est souvent supérieure à la différence annoncée entre deux supports.
Comment mesurer la capacité disque réellement disponible sur votre VPS
Installez fio, l’outil de référence pour les benchmarks IO, puis lancez les mesures. Trois précautions d’abord. Le test crée un fichier. Il utilise donc de l’espace disque et est comptabilisé dans les IOPS incluses dans votre facturation. Faites des exécutions courtes. Ne l’exécutez pas avec une profondeur de file maximale sur un volume qui sert du trafic en production. Vous entreriez en concurrence avec votre propre application.
sudo apt update && sudo apt install -y fio ioping sysstat
cd /var/tmpLecture aléatoire avec une profondeur de file de 32, la valeur indiquée par les fournisseurs :
fio --name=randread --filename=fio.test --size=1G --bs=4k --rw=randread \
--ioengine=libaio --direct=1 --iodepth=32 --numjobs=1 \
--runtime=30 --time_based --group_reportingLa ligne importante commence par read:
read: IOPS=184k, BW=719MiB/s (754MB/s)(21.1GiB/30001msec)--direct=1 contourne le cache de pages du guest. Le résultat décrit donc le périphérique plutôt que votre RAM. Si vous omettez cette option, vous mesurez la mémoire, qui renvoie une valeur qu’aucun disque ne peut atteindre. Utilisez --size=4G ou une valeur supérieure si vous disposez de suffisamment d’espace. Un fichier de 1G peut rester entièrement dans le cache de l’hôte et fausser le résultat à la hausse.
Une profondeur de file de 1 montre la latence brute, c’est-à-dire ce que ressent un processus monothread :
fio --name=lat --filename=fio.test --size=1G --bs=4k --rw=randread \
--ioengine=libaio --direct=1 --iodepth=1 --runtime=30 --time_basedLe test de commit permet d’estimer le comportement d’une base de données. Il écrit 4k, puis appelle fdatasync() après chaque écriture. Le débit indiqué inclut donc le flush :
fio --name=commit --filename=fio.test --size=1G --bs=4k --rw=randwrite \
--ioengine=psync --fdatasync=1 --runtime=30 --time_based
rm -f fio.testLe nombre d’IOPS obtenu lors de cette exécution est proche du nombre maximal de petites transactions par seconde qu’une connexion à la base de données peut valider. Un commit attend en effet le même flush.
Pour obtenir un échantillon rapide sans fio :
ioping -c 20 .--- . (ext4 /dev/vda1) ioping statistics ---
19 requests completed in 4.13 ms, 76 KiB read, 4.60 k iops, 17.9 MiB/s
min/avg/max/mdev = 174.2 us / 217.6 us / 386.1 us / 51.3 usLa valeur mdev, l’écart moyen, est aussi importante que la moyenne. Un écart élevé sur une machine inactive indique que le backend de stockage est partagé et sollicité.
Comment lire le résultat
En juillet 2026, voici des valeurs raisonnables pour un petit VPS. Des dizaines de milliers d’IOPS en lecture aléatoire 4k avec une profondeur de file de 32, et une latence inférieure à environ 0.3 ms avec une profondeur de file de 1, sont compatibles avec du flash local. Une latence de plusieurs millisecondes avec une profondeur de file de 1 indique un chemin réseau, quel que soit le nom de l’offre. Des lectures séquentielles qui plafonnent près de 550 MB/s sont caractéristiques d’une liaison SATA. Une valeur largement supérieure aux performances de n’importe quel périphérique unique indique la présence d’un cache dans le chemin, presque toujours sur l’hôte.
Pour voir l’effet de votre charge en cours sur le disque :
iostat -x 1 3
vmstat 1 5
cat /proc/pressure/ioDans la sortie de iostat -x, consultez r_await et w_await, qui indiquent le nombre moyen de millisecondes pendant lesquelles une requête a attendu, ainsi que aqu-sz, qui indique la longueur moyenne de la file. Ignorez %util sur un disque virtuel. Cette valeur indique la proportion du temps pendant laquelle au moins une requête était en attente. Elle ne dit rien de la saturation d’un périphérique capable de traiter de nombreuses requêtes simultanément. Ainsi, une valeur %util de 100 associée à une valeur r_await de 0.2 ms correspond à un disque actif dans un état normal. Dans vmstat, la colonne wa indique le pourcentage du temps CPU passé à attendre les opérations d’E/S. Si /proc/pressure/io existe sur votre kernel, sa valeur some avg10= indique la proportion des 10 dernières secondes pendant laquelle au moins une tâche était bloquée par des opérations d’E/S. C’est l’indicateur le plus direct pour déterminer si le stockage constitue votre goulot d’étranglement.
À quoi ressemble un VPS limité par le disque
Un load average élevé, un CPU inactif et un wa important dans vmstat indiquent que les processus attendent derrière le disque. Le signal le plus clair du kernel est ce message dans dmesg -T :
INFO: task jbd2/vda1-8:194 blocked for more than 120 seconds.Cette ligne apparaît parce qu’un thread du kernel a attendu plus de deux minutes une réponse du stockage. Le hung task watchdog l’a donc journalisé. jbd2 est le thread du journal ext4. Cela signifie que tout le système de fichiers attendait, et non qu’un seul programme se comportait mal. Sur un VPS, cela pointe généralement vers le backend de stockage ou vers une allowance IOPS épuisée.
Les symptômes côté application suivent le même schéma. Le temps de réponse médian reste acceptable, tandis que les requêtes les plus lentes forment une longue traîne, car seules les requêtes qui accèdent au disque en subissent le coût. apt upgrade reste bloqué sur Unpacking pendant plusieurs minutes, car dpkg effectue des flush lors de ses écritures. git status dans un dépôt volumineux prend plusieurs secondes. Il s’agit de coûts liés aux métadonnées et aux flush ; davantage de bandwidth n’y changerait rien.
Que faire lorsque le disque devient le facteur limitant
Achetez de la RAM avant d’acheter des IOPS. Si l’ensemble de travail tient dans le page cache, les lectures n’atteignent plus du tout le disque. Doubler la mémoire est souvent plus efficace que passer à une classe de stockage plus rapide, et coûte généralement moins cher.
Réduisez le nombre de flushes lorsque les données le permettent. Dans PostgreSQL, synchronous_commit = off permet à un commit de se terminer avant que l’écriture ne soit effectuée sur le disque. Si le serveur tombe en panne, vous pouvez perdre la dernière fraction de seconde de transactions. La base de données n’est pas corrompue, car le write-ahead log est toujours écrit dans l’ordre. Ce compromis convient à une copie destinée à l’analytics, mais pas aux paiements. innodb_flush_log_at_trx_commit = 2 dans MySQL applique le même compromis.
Regroupez les petits fichiers. Le transfert ou la sauvegarde d’un million de petits fichiers est principalement limité par le coût de traitement de chaque fichier. Il est donc plus rapide, sur un stockage à latence élevée, de créer d’abord une archive puis de transférer un seul flux plutôt que de copier l’arborescence fichier par fichier.
Maintenez le discard actif sur les volumes thin. Sur un stockage thin provisioned, le backend ne sait pas qu’un bloc est libre tant que le système de fichiers ne le lui indique pas. Un volume qui n’exécute jamais de trim perd progressivement en performances d’écriture. Ubuntu fournit un timer hebdomadaire pour cela :
systemctl status fstrim.timer
sudo fstrim -avfstrim -av affiche le nombre d’octets traités par le discard pour chaque point de montage. Un message indiquant que l’opération discard n’est pas prise en charge signifie que le disque virtuel ne transmet pas le discard à l’hôte. Vous n’avez donc rien à corriger.
Ne vous attardez pas sur le réglage de l’ordonnanceur IO. Sur un disque virtio, cat /sys/block/vda/queue/scheduler affiche généralement déjà none, et l’ordonnancement réel s’effectue sur l’hôte, auquel vous n’avez pas accès. Ignorez également noatime : Ubuntu monte par défaut avec relatime, ce qui évite déjà presque toutes les écritures liées à atime.
Choisir une offre
Payez pour du NVMe lorsqu’une base de données, un serveur de messagerie, un runner CI ou un build avec beaucoup de paquets s’exécute sur la machine. Ne payez pas plus cher pour un site web mis en cache ou pour une application dont le temps d’exécution est consacré aux appels externes. En cas de doute, le disque n’est probablement pas votre facteur limitant : la plupart des petites charges de travail sur VPS manquent d’abord de RAM ou de bande passante.
Effectuez les mesures dès le premier jour, pendant que vous suivez les dix premières minutes sur un nouveau VPS, et enregistrez la sortie dans un fichier. Une référence vous permet ensuite de démontrer que l’hôte est devenu plus lent, plutôt que votre code. Privilégiez les fournisseurs qui indiquent par écrit la classe de stockage et toute limite d’IOPS. Si une offre annonce du NVMe alors qu’une lecture avec une profondeur de file d’attente de 1 prend 4 ms, vous utilisez un stockage réseau sur un hôte équipé de NVMe. C’est une offre légitime, mais ce n’est pas le même produit.
FAQ
Un NVMe est-il toujours plus rapide qu’un SSD SATA sur un VPS ?
Non. Avec une profondeur de file d’attente de 1, les deux sont proches, autour de 80 à 150 microsecondes pour une lecture 4k, et un programme monothread ne peut pas les distinguer. NVMe prend l’avantage lorsque de nombreuses requêtes sont simultanément en attente, car AHCI propose une seule file de 32 commandes, tandis que NVMe propose des milliers de files plus profondes. Sur un hôte partagé, la charge générée par les autres guests peut modifier votre latence davantage que le support lui-même. Mesurez donc votre propre volume avec fio au lieu de vous fier au nom de l’offre.
Comment vérifier si mon VPS utilise réellement NVMe ?
Vous ne pouvez pas le vérifier directement, car virtio masque le périphérique physique. lsblk affiche vda sans chaîne de modèle, nvme list ne renvoie rien et /sys/block/vda/queue/rotational indique uniquement ce que l’hyperviseur annonce. Mesurez plutôt le comportement. Une lecture aléatoire 4k avec une profondeur de file d’attente de 1 et une latence inférieure à environ 0.3 ms indique un stockage flash local. Une latence de plusieurs millisecondes indique qu’un saut réseau intervient dans le chemin. Des lectures séquentielles qui plafonnent près de 550 MB/s indiquent une liaison SATA.
NVMe accélère-t-il le chargement de mon site web ?
En général, non. Après la première requête, Linux sert les fichiers depuis le page cache en RAM, et le disque devient donc inactif. Sur un petit VPS, les performances d’affichage dépendent normalement du temps CPU de l’application et de la bande passante. Le disque redevient critique si le site écrit à chaque requête, par exemple avec un panier basé sur une base de données qui effectue fréquemment des commits, car chaque commit attend la fin d’un flush.
Quel résultat fio est satisfaisant pour un VPS ?
En juillet 2026, un petit VPS utilisant un stockage flash local fournit généralement plusieurs dizaines de milliers d’IOPS en lecture aléatoire 4k avec une profondeur de file d’attente de 32, et une latence inférieure à 0.3 ms avec une profondeur de file d’attente de 1. Le stockage en mode bloc sur réseau fournit généralement quelques milliers d’IOPS, avec une latence de quelques millisecondes. Effectuez le test trois fois à des heures différentes. Un écart important entre les exécutions vous renseigne davantage que la moyenne, car il montre dans quelle mesure les autres guests de l’hôte vous affectent.
Dois-je placer ma base de données sur un stockage en mode bloc sur réseau ?
C’est possible, et de nombreux services managés le font, mais le chemin de commit en subit le coût. Chaque flush traverse le réseau. Une seule connexion effectue donc moins de petites transactions par seconde que sur un stockage flash local. En contrepartie, vous bénéficiez d’une durabilité qui subsiste à la perte de l’hôte. Si vous choisissez un stockage réseau pour une base de données fortement sollicitée en écriture, regroupez les opérations dans des transactions plus importantes afin que moins de flushes écrivent davantage de lignes.