Comment tester un NVMe avec fio sans confondre débit et latence
Lorsqu’un nouveau serveur doit héberger une base de données ou un service de fichiers, la vitesse obtenue en copiant un gros fichier ne suffit pas à valider le stockage. Les données peuvent être servies depuis le cache, les écritures ne pas encore être persistantes et les tâches en arrière-plan modifier les résultats. Une méthode plus fiable consiste à fixer le fichier de test, la taille des blocs et les paramètres de parallélisme, à examiner séparément le débit et la latence, puis à conserver les résultats bruts pour pouvoir reproduire les mesures.
Les serveurs dédiés CloudUDP sont équipés en standard de deux NVMe de 1TB, chacun connecté directement, sans RAID matériel. La procédure ci-dessous prend Debian 13 comme exemple et utilise fio, un outil de test de charge d’E/S configurable, pour tester un système de fichiers donné. Elle n’effectue aucune écriture sur un périphérique brut et ne présente pas les résultats comme une garantie de performances pour les applications en production.
1. Définir le périmètre du test et localiser les données sur le stockage
Un test sur fichier couvre le chemin allant du système de fichiers au stockage ; il ne mesure pas uniquement les limites du disque. Le chiffrement, la gestion des volumes, la mise en miroir et les options de montage peuvent tous influer sur les résultats. Le fait que les deux disques soient connectés directement ne signifie pas non plus qu’un répertoire donné utilise les deux.
Installez d’abord l’outil et vérifiez le répertoire cible. Dans cet exemple, /srv est l’emplacement envisagé pour le test, à confirmer. S’il ne se trouve pas sur le système de fichiers à tester, remplacez-le par le répertoire de montage approprié.
sudo apt-get install fio
findmnt -T /srv -o TARGET,SOURCE,FSTYPE,OPTIONS
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
df -h /srv
df -i /srv
fio --version
Vérifiez l’espace disponible, l’état du montage et les droits d’accès au répertoire. Ne vous fiez pas uniquement à la capacité nominale du disque : les structures du système de fichiers et les données existantes occupent une partie de l’espace. Une fois le fichier de test entièrement rempli, il doit encore rester une marge pour la croissance des données de production.
Ne fournissez pas de chemin de périphérique tel que
/dev/nvme…à un test d’écriture. Un fichier distinct réduit le risque d’écrasement accidentel, mais n’élimine pas la contention sur les ressources. Effectuez de préférence les tests avant la mise en production. Arrêtez-les immédiatement si la latence des services devient anormale, si l’espace libre approche du seuil de réserve ou si des erreurs d’E/S apparaissent.
2. Créer un répertoire isolé et préparer intégralement le fichier de test
Exécutez toutes les commandes dans la même session Bash. Avec les droits d’administration, créez un répertoire temporaire réservé au compte utilisateur courant. Placez-y le fichier de test et les résultats pour ne pas toucher aux fichiers de production existants.
TESTDIR=$(sudo mktemp -d /srv/fio-acceptance.XXXXXX)
sudo chown "$(id -u):$(id -g)" "$TESTDIR"
chmod 700 "$TESTDIR"
export TESTDIR
printf '%s\n' "$TESTDIR"
findmnt -T "$TESTDIR"
L’exemple utilise un fichier de 1GiB. C’est un point de départ pour valider la procédure, pas une mesure de toute la capacité de stockage ni du comportement en régime stable sur une longue durée. fio interprète size=1G en unités binaires : cette valeur ne doit pas être comparée à la capacité nominale du périphérique sans tenir compte des unités. Après avoir confirmé que l’espace est suffisant, remplissez entièrement le fichier par une écriture séquentielle :
fio --name=prepare \
--filename="$TESTDIR/test.bin" \
--size=1G --rw=write --bs=1M \
--ioengine=libaio --direct=1 \
--iodepth=1 --numjobs=1 --end_fsync=1 \
--group_reporting --output-format=json \
--output="$TESTDIR/prepare.json"
Vérifiez impérativement le code de sortie et les champs d’erreur du JSON. Si les E/S directes ne sont pas prises en charge, examinez d’abord le système de fichiers et son mode de montage. Ne passez pas discrètement à des E/S avec cache tout en continuant à comparer les résultats. Si la préparation rencontre des erreurs, les tests de lecture suivants ne reposent pas sur une base fiable.
direct=1 contourne généralement le cache de pages des données de fichiers, mais pas tous les caches du périphérique. end_fsync=1 demande une synchronisation à la fin de la tâche ; cela ne signifie pas que chaque écriture simule la validation d’une transaction de base de données.
3. Fixer les paramètres et tester séparément la lecture et l’écriture aléatoires
Commencez par une lecture aléatoire avec une seule tâche, puis effectuez une écriture aléatoire, afin qu’une charge mixte ne masque pas les problèmes. Pendant le test, ne copiez pas de données et ne lancez pas d’autres tests de stockage.
fio --name=randread \
--filename="$TESTDIR/test.bin" \
--size=1G --rw=randread --bs=4k \
--ioengine=libaio --direct=1 \
--iodepth=8 --numjobs=1 \
--time_based --runtime=30 --ramp_time=5 \
--group_reporting --output-format=json \
--output="$TESTDIR/randread-q8.json"
fio --name=randwrite \
--filename="$TESTDIR/test.bin" \
--size=1G --rw=randwrite --bs=4k \
--ioengine=libaio --direct=1 \
--iodepth=8 --numjobs=1 \
--time_based --runtime=30 --ramp_time=5 \
--end_fsync=1 --group_reporting \
--output-format=json \
--output="$TESTDIR/randwrite-q8.json"
La durée d’exécution et la période de montée en charge indiquées ici ne sont que des paramètres de test. Un test court peut être influencé par le cache du périphérique, sa température et les opérations de maintenance en arrière-plan. Il ne permet pas de déduire les performances d’écriture sur une longue durée.
Ajouter un test comparatif à faible profondeur de file
Dans le test de lecture, remplacez iodepth par 1 et utilisez randread-q1.json comme fichier de sortie, sans modifier les autres paramètres. La profondeur de file correspond au nombre de requêtes d’E/S pouvant être simultanément en attente de completion. Ce n’est ni le nombre de cœurs CPU ni le nombre de connexions simultanées à un service.
Si l’augmentation de la profondeur de file améliore le débit mais dégrade nettement la latence de queue de distribution, elle indique seulement un compromis entre débit et temps d’attente pour cette charge. Ne transposez pas directement ce réglage au pool de connexions d’une base de données.
4. Analyser ensemble le débit, les IOPS et la latence de queue de distribution
Les IOPS représentent le nombre d’opérations d’E/S terminées par seconde. À taille de bloc constante, elles sont liées au débit ; des résultats obtenus avec des tailles de bloc différentes ne doivent pas être classés sur le seul critère des IOPS. Dans le JSON de fio, bw est généralement exprimé en KiB/s. Vérifiez la version et les unités des champs lors de l’analyse.
Examinez en priorité iops, les champs de débit, ainsi que la moyenne et les percentiles de clat_ns dans les sections read ou write. La latence de completion ne correspond pas exactement au temps de réponse de l’application : l’attente dans les files de l’application et son propre traitement restent en dehors de cette mesure.
Le P99 signifie qu’environ 99 % des requêtes ont une latence inférieure ou égale à cette valeur. Ce n’est pas la latence maximale. Si les moyennes sont proches mais que le P99 augmente, une petite proportion des requêtes peut subir une attente plus longue. Il faut l’évaluer en tenant compte de la profondeur de file réelle et de tests répétés.
Le compte rendu de validation doit inclure au minimum :
- La version de fio, les commandes complètes, la taille du fichier et les informations sur le montage cible.
- Le type de lecture et d’écriture, la taille des blocs, le nombre de tâches et la profondeur de la file de requêtes.
- Le débit, les IOPS, la latence moyenne de completion et le P99.
- Les champs d’erreur, la charge de production pendant le test et les anomalies constatées.
Consultez également la distribution de la profondeur d’E/S réellement atteinte dans fio. Une valeur configurée à 8 ne signifie pas que cette profondeur a été maintenue pendant toute l’exécution. Si le moteur d’E/S ou le système de fichiers se comporte différemment, des paramètres nominaux identiques ne garantissent pas des résultats comparables.
5. Finaliser la validation par des répétitions, l’archivage et le nettoyage
Répétez chaque charge en utilisant des noms de fichiers de sortie différents, sans écraser les résultats précédents. Comparez l’étendue des variations plutôt que de retenir le chiffre le plus élevé. Avant d’augmenter la taille du fichier ou la durée du test, vérifiez de nouveau l’espace disponible et évaluez le volume d’écriture supplémentaire ainsi que la contention sur les ressources.
Si les deux disques doivent être validés séparément, choisissez un répertoire sur le système de fichiers de chacun, puis exécutez les tests l’un après l’autre avec les mêmes paramètres. Si les répertoires se trouvent en réalité sur le même volume, changer de répertoire ne constitue pas une validation indépendante du second disque.
En cas d’erreur pendant les tests de lecture ou d’écriture, conservez d’abord les sorties brutes et les journaux du noyau pertinents, puis examinez le système de fichiers et la chaîne de connexion du périphérique. Si aucune erreur n’apparaît mais que les résultats varient fortement, écartez d’abord l’influence des autres tâches sur le serveur et des changements de conditions de test. Ne concluez pas immédiatement à un défaut matériel.
Une fois les tests terminés, copiez les JSON, les informations de montage et les commandes consignées vers un emplacement d’archivage contrôlé. Vérifiez que l’archive est lisible, puis contrôlez le répertoire de test et supprimez uniquement le fichier créé pour cette procédure :
printf '%s\n' "$TESTDIR"
ls -lh -- "$TESTDIR"
rm -- "$TESTDIR/test.bin"
Après avoir confirmé que les fichiers de résultats restants sont archivés, supprimez-les un par un. Lorsque le répertoire est vide, supprimez-le avec rmdir ; n’utilisez pas de suppression récursive sur les points de montage des périphériques. La conclusion doit être formulée ainsi : « ces résultats ont été obtenus avec ces paramètres et dans ces conditions de charge », et non « ce disque atteint toujours telle vitesse ». Les mesures de référence sur fichiers servent à détecter les écarts manifestes ; avant la mise en production d’une application, une validation avec ses véritables profils de lecture et d’écriture reste nécessaire.
Questions fréquentes
Un test fio sur fichier est-il sans effet sur les services en production ?
Non. Un fichier dédié évite d’écraser directement les fichiers existants, mais le test utilise toujours le disque, le CPU et le système de fichiers. Tester avant la mise en service ou définir l’impact acceptable et les critères d’arrêt.
direct=1 contourne-t-il tous les caches et mesure-t-il les validations de transactions ?
Non. Les entrées-sorties directes contournent généralement le cache de pages des données de fichiers, pas tous les caches du périphérique. La persistance des transactions demande un test distinct de l’application et des écritures synchronisées.
Serveur dédié AMD EPYC 7543P, à partir de $454/mois