« Il indique 1 000 000 FPS. » C’est comme ça que ça commence. Une diapositive, un fichier d’achat, un manager qui veut juste clore le ticket, et un système de stockage qui—mystérieusement—n’arrive pas à maintenir une base de données sous 30 ms en pointe.
Le « FPS marketing » (appelez-le IOPS, FPS, transactions, « ops » ou « jusqu’à ») est le chiffre que les vendeurs sortent quand ils veulent que vous arrêtiez de poser des questions. La production s’en fiche. La production veut de la latence sous charge, le comportement des queues, le mix lecture/écriture, le working set, et ce qui se passe après que le cache est froid et que le système est moyennement mécontent.
Ce que « FPS marketing » signifie réellement (et ce qu’il cache)
Quand un vendeur annonce « 1M IOPS » (ou son « FPS » rebrandé), ajoutez mentalement les notes de bas de page manquantes :
- Taille de bloc : presque toujours 4K (les petits blocs gonflent le nombre d’opérations).
- Patron : lecture aléatoire (les lectures sont plus faciles que les écritures ; l’aléatoire masque les limites de débit séquentiel).
- Profondeur de file (queue depth) : élevée (des files profondes augmentent les IOPS pendant que la latence explose en silence).
- Cache : chauffé, et parfois sans toucher réellement le média.
- Ensemble de données : tient dans le cache ou dans un buffer SLC, bien pratique.
- Durée : assez courte pour éviter le comportement en steady-state (surtout pour le NAND et la collecte des ordures).
- Disques : le modèle « top bin », pas celui qu’on vous livrera après un trimestre d’« ajustements » de chaîne d’approvisionnement.
- Hôte : un serveur de benchmark réglé comme une voiture de course, pas votre ferme de VM.
Les chiffres marketing ne sont pas toujours des mensonges. Ils sont souvent vrais pour un scénario étroit et soigné. Le problème est que les équipes d’achats les considèrent comme une garantie pour votre charge de travail.
Voici la réalité : les IOPS ne sont pas une métrique de capacité. C’est un point sur une courbe. Changez une variable—taille de bloc, mix lecture/écriture, profondeur de file, localité des données—et vous êtes sur une autre courbe.
Un contrôle de bon sens : si un appareil promet des IOPS énormes mais ne déplace pas beaucoup de bande passante, c’est probablement un titre 4K. Exemple : 1 000 000 IOPS en 4K correspond à environ 4 GB/s. C’est réel, mais uniquement si tout le reste coopère et que vous pouvez l’alimenter.
Blague #1 : « Jusqu’à 1M IOPS » c’est comme « jusqu’à 200 mph » sur une voiture de location—techniquement possible, socialement déconseillé, et non couvert par la garantie.
Règles simples pour éviter les ennuis
Règle 1 : Si vous n’avez pas de percentiles de latence, vous n’avez pas de revendication de performance
Demandez P50, P95, P99 de latence aux IOPS revendiqués. La latence moyenne est une histoire pour s’endormir ; la latence de queue est l’intrigue. Si le vendeur ne fournit pas les percentiles sous les mêmes conditions, traitez le chiffre IOPS comme décoratif.
Règle 2 : Traitez la profondeur de file comme un bouton qui échange latence contre IOPS en une ligne
Les files profondes augmentent les IOPS et rendent les utilisateurs malheureux. Votre application ne tourne généralement pas à QD=128 par périphérique. Bases de données, moteurs de recherche et services requête/réponse ont souvent une concurrence limitée et tiennent à une faible latence à QD modéré, pas au « rendement maximal à n’importe quel prix ».
Règle 3 : Séparez « burst » et « soutenu »
Les NVMe, arrays et volumes cloud peuvent paraître héroïques pendant 10–60 secondes. Puis ils retombent à leur état stable. Exigez au moins 30 minutes de test pour les revendications orientées écriture, et assurez-vous que l’appareil est en steady state (plus bas quelques détails).
Règle 4 : Si l’ensemble de données tient dans le cache, vous testez le cache
Le cache, c’est bien. Acheter du stockage pour faire office de cache, c’est aussi bien—si c’est ce que vous voulez. Mais ne testez pas 20 GB sur un système avec 512 GB de RAM et n’appelez pas ça la « performance disque ». C’est la « performance RAM avec étapes additionnelles ».
Règle 5 : Exigez la recette complète du test (taille de bloc, mix rw, QD, threads, durée, préconditionnement)
Un chiffre seul sans la recette n’est pas un benchmark ; c’est un slogan. Demandez un fichier job fio reproductible ou équivalent. S’ils ne peuvent pas vous le fournir, leur chiffre n’est pas utile pour des décisions d’ingénierie.
Règle 6 : Utilisez « latence à débit requis » comme objectif de dimensionnement
Vous n’achetez pas le « maximum d’IOPS ». Vous achetez la capacité de rester sous, par exemple, 5 ms P99 à votre charge mixte de pointe. Commencez par vos SLO et travaillez à rebours.
Règle 7 : Surveillez l’amplification d’écriture et la collecte des ordures
Les systèmes flash peuvent se dégrader sous des écritures aléatoires soutenues, surtout près d’une forte utilisation. Préconditionnez les disques. Testez à des niveaux de remplissage réalistes. Demandez au vendeur ce qui se passe à 70% plein, pas à 7%.
Règle 8 : Si la revendication ignore l’hôte, elle est incomplète
Drivers, multipathing, CPU, NUMA, gestion des interruptions, système de fichiers et chiffrement peuvent devenir des goulots bien avant le média. Une revendication de stockage qui ne spécifie pas le matériel et le logiciel hôte n’est que la moitié d’une revendication.
Règle 9 : « IOPS » sans mix lecture/écriture est dénué de sens
70/30 lecture/écriture ne se comporte pas du tout comme 100% lecture. Ni comme 30/70. Si votre charge est mixte, votre benchmark doit être mixte, et vos critères d’acceptation aussi.
Règle 10 : Testez toujours le mode défaillance que vous ne pouvez pas éviter
Les reconstructions arrivent. Le scrubbing en arrière-plan arrive. Un chemin échoue. Un contrôleur redémarre. Si vous ne testez que les jours ensoleillés, la production planifiera un orage.
Faits intéressants et contexte (le marketing du stockage a une histoire)
- Fait 1 : Les « IOPS » sont devenus célèbres parce que les premiers arrays pouvaient masquer de terribles temps de seek derrière du caching et des plateaux parallèles—les vendeurs avaient donc besoin d’un nombre unique comptable pour l’accès aléatoire.
- Fait 2 : L’industrie s’est standardisée sur le 4K random read pour les IOPS en titre en partie parce que cela correspond aux tailles de page de base de données et gonfle le nombre d’opérations comparé au 8K/16K.
- Fait 3 : Les benchmarks de stockage ont fait l’objet de controverses depuis l’époque de SPEC et TPC ; les vendeurs ont longtemps optimisé des configurations pour gagner des runs de benchmark plutôt que pour correspondre à des déploiements typiques.
- Fait 4 : Beaucoup de SSD utilisent un cache d’écriture SLC (même quand le NAND est TLC/QLC). Il peut produire des rafales spectaculaires qui disparaissent en steady state.
- Fait 5 : Le NAND nécessite un erase-before-write au niveau des blocs ; la collecte des ordures et le wear leveling expliquent pourquoi la performance d’écriture aléatoire en steady-state est souvent bien plus basse que « sortie d’usine ».
- Fait 6 : La profondeur de file est devenue un levier marketing quand NVMe a rendu la parallélisme profonde bon marché ; un QD élevé peut maintenir l’appareil occupé, mais masque aussi les pics de latence jusqu’à ce que votre appli lâche.
- Fait 7 : À l’époque des HDD, un disque « 15K RPM » faisait environ 175–210 IOPS aléatoires ; les arrays atteignaient des dizaines de milliers en répartissant sur de nombreux spindles et en mettant en cache agressivement.
- Fait 8 : Les volumes cloud ont souvent des crédits de burst explicites ou des plafonds de débit ; la performance peut être contractuelle mais limitée dans le temps, ce qui rend les benchmarks courts trompeurs.
- Fait 9 : Les premiers contrôleurs RAID avec cache d’écriture protégé par batterie pouvaient rendre les écritures rapides jusqu’à la vidange du cache ; le « cliff » de latence surprise est plus ancien que beaucoup d’équipes SRE actuelles.
Les seules métriques qui comptent dans les systèmes réels
1) Percentiles de latence (P50/P95/P99) dans le temps
Vous voulez une série temporelle, pas un seul résumé. Si P99 monte pendant le run, vous observez l’épuisement du cache, du thermal throttling, la collecte des ordures ou du travail en arrière-plan.
2) IOPS et bande passante ensemble
Les IOPS sans MB/s donnent un système beau sur papier qui ne peut pas faire de sauvegardes. Le débit sans IOPS donne un système qui stream bien mais bloque sur les métadonnées.
3) Profondeur de file et concurrence
Mesurez la file d’IO que vous utilisez réellement. Si l’appli n’a que 16 IO en attente par nœud, un benchmark à QD=256 est sans objet.
4) Mix lecture/écriture et localité
Aléatoire vs séquentiel n’est pas binaire. Beaucoup de charges sont « majoritairement séquentielles avec des métadonnées aléatoires gênantes », ce qui explique pourquoi elles vont bien jusqu’au jour où elles ne vont plus bien.
5) Steady state et niveau de remplissage
Testez à une utilisation réaliste et après préconditionnement. La performance flash varie énormément selon le niveau de remplissage et le degré de « saleté ».
6) Queue de queue sous contention
La production a des voisins : compaction en arrière-plan, snapshots, rebuilds, scrubs, antivirus, log shipping, autres locataires et vos propres fenêtres de patch. Vous avez besoin de chiffres sous douleur légère, pas seulement sans douleur.
Une idée paraphrasée, parce qu’elle est trop vraie pour être ignorée : paraphrased idea
— Gene Kranz (directeur de vol NASA) est souvent associé à « l’échec n’est pas une option », ce qui en ops se traduit par « testez le chemin moche maintenant, pas plus tard ».
Tâches pratiques : commandes, sorties et la décision que vous prenez
Voici le type de vérifications que vous pouvez exécuter sur un hôte Linux pour éviter d’être hypnotisé par un seul nombre IOPS. Chaque tâche inclut : une commande, ce que signifie une sortie typique, et la décision que vous prenez.
Task 1: Identify the storage device and its model (don’t benchmark the wrong thing)
cr0x@server:~$ lsblk -o NAME,MODEL,SIZE,ROTA,TYPE,MOUNTPOINT,FSTYPE
NAME MODEL SIZE ROTA TYPE MOUNTPOINT FSTYPE
nvme0n1 Samsung SSD 990 PRO 1.8T 0 disk
├─nvme0n1p1 512M 0 part /boot ext4
└─nvme0n1p2 1.8T 0 part /data xfs
Ce que cela signifie : Vous êtes sur NVMe (ROTA=0), le modèle est visible, et vous voyez où il est monté.
Décision : Benchmarquez le périphérique brut ou un fichier de test dédié sur le système de fichiers correct. Si le modèle n’est pas celui attendu, arrêtez et corrigez les hypothèses d’achat/installation hôte.
Task 2: Confirm the kernel sees NVMe at the expected link speed and width
cr0x@server:~$ sudo nvme id-ctrl /dev/nvme0 | egrep -i 'mn|fr|mdts'
mn : Samsung SSD 990 PRO 2TB
fr : 5B2QJXD7
mdts : 9
Ce que cela signifie : Modèle/firmware corrects ; MDTS indique la taille de transfert max. Ce n’est pas la vérification complète du lien, mais un contrôle d’identité basique.
Décision : Si l’identité du device est inattendue, n’allez pas plus loin. Un firmware erroné peut aussi signifier des comportements connus de throttling/bugs ; alignez avec votre baseline plateforme.
Task 3: Check if the drive is thermally throttling (classic “benchmark starts fast, ends sad”)
cr0x@server:~$ sudo nvme smart-log /dev/nvme0 | egrep -i 'temperature|warning|critical'
temperature : 71 C
warning_temp_time : 12
critical_comp_time : 0
Ce que cela signifie : Le disque a atteint la température d’avertissement pendant 12 minutes. C’est un gros indicateur de throttling.
Décision : Corrigez le refroidissement/le flux d’air/le placement du slot avant de croire à tout test de performance « soutenue ».
Task 4: Verify filesystem mount options (you can accidentally benchmark journaling or barriers)
cr0x@server:~$ mount | grep ' /data '
/dev/nvme0n1p2 on /data type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
Ce que cela signifie : XFS avec options plutôt par défaut ; rien d’évidemment cassé.
Décision : Si vous voyez des options inattendues (par ex. sync, ou des modifications exotiques de barriers), alignez avec la configuration de production avant de tester.
Task 5: See if you’re already IO-limited (high utilization) before running fio
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 01/21/2026 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.1 0.0 4.2 8.7 0.0 75.0
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s w_await aqu-sz %util
nvme0n1 9.0 320.0 0.0 0.0 1.2 35.6 220.0 8200.0 6.9 1.8 92.4
Ce que cela signifie : %util à ~92% indique que le périphérique est proche de la saturation. w_await est 6.9 ms, et l’iowait n’est pas négligeable.
Décision : Si c’est un hôte de production, vous êtes peut-être déjà à la limite—benchmarquer maintenant mélangera le bruit de la charge aux résultats. Pour le dépannage : concentrez-vous sur qui fait de l’IO et si la latence correspond à votre SLO.
Task 6: Find which processes are generating IO (don’t blame storage for an app bug)
cr0x@server:~$ sudo iotop -o -b -n 3
Total DISK READ: 0.00 B/s | Total DISK WRITE: 62.31 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
14221 be/4 postgres 0.00 B/s 41.72 M/s 0.00 % 65.12 % postgres: checkpointer
18802 be/4 root 0.00 B/s 18.49 M/s 0.00 % 22.30 % /usr/bin/rsync -a /var/lib/app/ /backup/
Ce que cela signifie : Postgres checkpointer et un rsync effectuent la plupart des écritures. C’est explicable, pas mystérieux.
Décision : Corrigez la planification/la coordination (déplacez la sauvegarde, ajustez le checkpointing) avant de dépenser de l’argent en stockage.
Task 7: Measure latency directly with fio (and record percentiles)
cr0x@server:~$ sudo fio --name=randread4k --filename=/data/fio.test --size=40G --direct=1 --rw=randread --bs=4k --iodepth=16 --numjobs=4 --runtime=120 --time_based --group_reporting --ioengine=libaio --percentile_list=50:95:99:99.9
randread4k: (groupid=0, jobs=4): err= 0: pid=21401: Tue Jan 21 11:10:10 2026
read: IOPS=185k, BW=723MiB/s (758MB/s)(84.7GiB/120001msec)
clat (usec): min=62, max=4210, avg=334.18, stdev=91.22
lat (usec): min=64, max=4215, avg=336.49, stdev=91.30
clat percentiles (usec):
| 50.000000th=[ 331], 95.000000th=[ 470], 99.000000th=[ 620], 99.900000th=[ 980]
Ce que cela signifie : Bons IOPS, et surtout, le P99 est 620 µs à cette charge. C’est un chiffre d’ingénierie réel.
Décision : Si votre appli a besoin de <2 ms, c’est acceptable. Si vous avez besoin de <200 µs, réduisez la profondeur de file, changez d’architecture, ou utilisez un média/topologie plus rapide.
Task 8: Show how queue depth inflates IOPS while latency worsens
cr0x@server:~$ sudo fio --name=randread4k_qd128 --filename=/data/fio.test --size=40G --direct=1 --rw=randread --bs=4k --iodepth=128 --numjobs=4 --runtime=120 --time_based --group_reporting --ioengine=libaio --percentile_list=50:95:99
randread4k_qd128: (groupid=0, jobs=4): err= 0: pid=21455: Tue Jan 21 11:13:01 2026
read: IOPS=420k, BW=1641MiB/s (1721MB/s)(192GiB/120001msec)
clat (usec): min=85, max=25000, avg=1188.74, stdev=655.10
clat percentiles (usec):
| 50.000000th=[ 1056], 95.000000th=[ 2200], 99.000000th=[ 3900]
Ce que cela signifie : Les IOPS ont plus que doublé, mais la latence médiane est maintenant ~1 ms et le P99 est 3.9 ms. Voilà le piège du « FPS marketing » en une image.
Décision : Choisissez la QD qui correspond à votre charge. Pour les services sensibles à la latence, acceptez moins d’IOPS pour maintenir la latence tail dans le SLO.
Task 9: Test mixed workload (70/30) because that’s what real life looks like
cr0x@server:~$ sudo fio --name=mix70_30 --filename=/data/fio.test --size=80G --direct=1 --rw=randrw --rwmixread=70 --bs=8k --iodepth=32 --numjobs=8 --runtime=300 --time_based --group_reporting --ioengine=libaio --percentile_list=50:95:99
mix70_30: (groupid=0, jobs=8): err= 0: pid=21510: Tue Jan 21 11:20:01 2026
read: IOPS=110k, BW=859MiB/s (901MB/s)
clat percentiles (usec):
| 50.000000th=[ 540], 95.000000th=[ 1500], 99.000000th=[ 2800]
write: IOPS=47.1k, BW=368MiB/s (386MB/s)
clat percentiles (usec):
| 50.000000th=[ 810], 95.000000th=[ 2600], 99.000000th=[ 5200]
Ce que cela signifie : Les écritures sont plus lentes et ont une pire latence tail. C’est normal—et c’est pourquoi « 100% read IOPS » ne sert pas à dimensionner une base de données.
Décision : Si le P99 des écritures est trop élevé, réduisez l’amplification d’écriture (batching, placement du WAL), ajoutez des périphériques, ou migrez vers un système optimisé pour la consistance des écritures.
Task 10: Precondition an SSD before trusting sustained write tests
cr0x@server:~$ sudo fio --name=precond --filename=/dev/nvme0n1 --direct=1 --rw=write --bs=1M --iodepth=32 --numjobs=1 --runtime=1800 --time_based --ioengine=libaio --group_reporting
precond: (groupid=0, jobs=1): err= 0: pid=21602: Tue Jan 21 12:00:01 2026
write: IOPS=2900, BW=2900MiB/s (3041MB/s)(5100GiB/1800000msec)
Ce que cela signifie : Vous avez écrit ~5 TB sur 30 minutes ; vous poussez le disque dans un état plus réaliste pour des tests d’écritures aléatoires ultérieurs.
Décision : Si vous ne pouvez pas préconditionner (parce que c’est du production partagé), vous ne pouvez pas honnêtement revendiquer une performance d’écriture « soutenue » à partir d’un benchmark court.
Task 11: Detect read-ahead or page cache cheating (accidental or deliberate)
cr0x@server:~$ sudo fio --name=cached-read --filename=/data/fio.test --size=4G --rw=read --bs=1M --iodepth=1 --numjobs=1 --runtime=30 --time_based --group_reporting
cached-read: (groupid=0, jobs=1): err= 0: pid=21688: Tue Jan 21 12:10:01 2026
read: IOPS=9200, BW=9200MiB/s (9647MB/s)(270GiB/30001msec)
Ce que cela signifie : 9.2 GiB/s depuis un seul NVMe dans un serveur typique est… suspect. Vous lisez depuis le cache (page cache) parce que le direct IO n’a pas été utilisé et que l’ensemble de données est petit.
Décision : Ajoutez --direct=1, augmentez l’ensemble de données au-delà de la RAM, et relancez. N’utilisez pas ce résultat pour le dimensionnement de stockage.
Task 12: Check whether the device is the bottleneck or CPU is
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (server) 01/21/2026 _x86_64_ (32 CPU)
11:25:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
11:25:02 AM all 38.2 0.0 18.9 0.7 0.0 2.1 0.0 40.1
11:25:02 AM 7 92.0 0.0 6.0 0.0 0.0 0.0 0.0 2.0
Ce que cela signifie : Un CPU est saturé. Cela peut être l’affinité IRQ, un job fio single-threadé piné, ou un driver limitant.
Décision : Si le CPU est saturé, « un stockage plus rapide » n’aidera pas. Corrigez le pinning CPU, la répartition des IRQ, ou augmentez la parallélisme correctement.
Task 13: Look for IO scheduler and queue settings (small knobs, big consequences)
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
Ce que cela signifie : NVMe utilise none (souvent correct). D’autres schedulers peuvent changer la distribution de latence.
Décision : Ne faites pas de cargo-cult. Si vous avez des problèmes de latence tail sous charge mixte, testez mq-deadline/kyber avec votre profil réel de workload et mesurez les percentiles.
Task 14: Validate that TRIM/discard isn’t sabotaging you (or that it exists when you need it)
cr0x@server:~$ lsblk -D -o NAME,DISC-GRAN,DISC-MAX,DISC-ZERO
NAME DISC-GRAN DISC-MAX DISC-ZERO
nvme0n1 512B 2T 0
Ce que cela signifie : Discard est supporté. Bien—maintenant vous pouvez choisir comment l’utiliser (fstrim périodique vs discard continu).
Décision : Si vous avez une dégradation d’écritures soutenues, envisagez un fstrim planifié hors-pointe et confirmez qu’il ne coïncide pas avec des fenêtres IO critiques.
Task 15: Observe per-device latency in real time during an incident
cr0x@server:~$ sudo pidstat -d 1 3
Linux 6.5.0 (server) 01/21/2026 _x86_64_ (32 CPU)
11:40:01 AM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
11:40:02 AM 999 14221 0.00 48200.00 0.00 postgres
11:40:02 AM 0 18802 0.00 20600.00 0.00 rsync
Ce que cela signifie : Vous pouvez corréler des rafales IO avec l’activité des processus, ce qui transforme « le stockage est lent » en « ces deux processus se percutent ».
Décision : Mettez en place de l’ordonnancement IO, des cgroups, ou des fenêtres de maintenance. Ne commencez pas par une migration de stockage avant d’avoir prouvé la saturation du média.
Task 16: Check md RAID rebuild or background tasks (the invisible performance tax)
cr0x@server:~$ cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 sdb1[0] sdc1[1]
976630336 blocks super 1.2 [2/2] [UU]
[======>..............] resync = 34.1% (333333333/976630336) finish=120.2min speed=89000K/sec
Ce que cela signifie : Resync en cours. Votre performance « normale » n’est pas disponible maintenant.
Décision : Ajustez les limites de vitesse de rebuild, reportez les jobs lourds, ou acceptez une dégradation temporaire du SLO. Aussi : intégrez les tests de rebuild dans vos benchmarks pré-achat.
Mode d’emploi de diagnostic rapide : trouver le goulot vite
Voici la checklist à utiliser quand quelqu’un signale « le stockage est lent » et que vous avez 10 minutes avant que le canal d’incident ne devienne une danse interprétative.
Première étape : confirmez que c’est la latence stockage, pas le temps d’application
- Vérifiez les découpages de latence des requêtes (métriques appli) si disponibles.
- Sur l’hôte, vérifiez
iostat -xz 1pour await, aqu-sz et %util. - Si %iowait est élevé mais %util est bas, suspectez quelque chose en amont (chemin stockage réseau, throttling, ou limites par cgroup).
Deuxième étape : identifiez la classe de contrainte (périphérique, chemin, CPU, ou politique)
- Contrainte périphérique : %util ~100%, await qui monte avec la charge, fio reproduit sur le même LUN/périphérique.
- Contrainte chemin : problèmes multipath, erreurs de lien, congestion ; pics de latence sans %util local saturé.
- Contrainte CPU : un cœur saturé (interrupts, chiffrement, checksums), stockage sous-utilisé.
- Contrainte politique : cap IOPS de volume cloud, QoS SAN, noisy neighbor throttling.
Troisième étape : prouvez-le avec un test ciblé
- Lancez un court test fio en lecture avec
--direct=1sur le volume affecté, en faisant correspondre la taille de bloc et la QD qui ressemblent à la charge. - Comparez aux chiffres de référence que vous faites confiance (depuis vos propres runbooks, pas une diapositive vendeur).
- Si fio est OK mais l’appli est lente, le goulot est probablement dans l’appli, les métadonnées du système de fichiers, la contention de verrous, ou le chemin réseau.
Quatrième étape : décidez de la mitigation la plus rapide et sûre
- Réduire les IO concurrents (pausez les jobs batch, ralentissez les rebuilds, déplacez les backups).
- Réduire l’amplification d’écriture (tuning checkpoint, batching, rythme des compactions).
- Scale-out des lectures (réplicas) ou sharding des partitions chaudes.
- Seulement après : scale-up du stockage ou migration.
Blague #2 : Si le benchmark vendeur dit « latence zéro », ils ont accidentellement mesuré l’empathie de l’équipe commerciale.
Erreurs courantes : symptôme → cause racine → solution
1) « Nous avons atteint les IOPS annoncées, mais l’appli est plus lente »
Symptôme : fio à QD=256 montre des IOPS énormes ; l’appli timeout ou le P99 explose.
Cause racine : L’appli tourne à faible concurrence ; les benchmarks à files profondes ont troqué latence contre IOPS.
Solution : Benchmarquez à une QD réaliste (souvent 1–32) et dimensionnez pour la latence P99 à cette QD. Si vous avez besoin à la fois de faible latence et de haut débit, scalez horizontalement ou utilisez plusieurs périphériques/chemins.
2) « C’était rapide hier ; aujourd’hui c’est à moitié vitesse »
Symptôme : La performance d’écritures aléatoires soutenues chute après un certain runtime ou à un remplissage plus élevé.
Cause racine : Disque sorti d’usine vs steady-state, garbage collection, épuisement du cache SLC, ou pression sur un pool thin-provisioned.
Solution : Préconditionnez, testez plus longtemps, testez à un remplissage réaliste, et assurez une surprovisionnement adéquat. Envisagez une stratégie TRIM périodique et évitez d’exploiter les pools à la limite.
3) « Les lectures vont bien ; les écritures bloquent parfois pendant des secondes »
Symptôme : Plutôt OK, puis des pics périodiques de latence de plusieurs secondes sur les écritures.
Cause racine : Événements de vidage de cache (cache flush), commits de journal, destage du contrôleur, ou pression sur les métadonnées du système de fichiers.
Solution : Vérifiez les réglages de writeback, la politique de cache du contrôleur, la taille du journal du système de fichiers, et si des tâches en arrière-plan (snapshots, scrub) coïncident avec les stalls.
4) « Ajouter une optimisation a empiré la performance »
Symptôme : Après un tuning « pour la vitesse », la latence tail s’est aggravée ou le throughput a baissé.
Cause racine : Options de montage mal appliquées, mauvais IO scheduler, readahead trop agressif, ou surcharge de compression/chiffrement sur des chemins chauds.
Solution : Revenez en arrière, puis testez les changements un par un avec les percentiles. Traitez le tuning comme des expériences, pas des croyances.
5) « Le SAN est lent, mais les tableaux de bord de l’array disent tout est vert »
Symptôme : L’hôte montre un await élevé ; l’array montre une faible utilisation.
Cause racine : Problèmes de chemin (multipath mal configuré), congestion, retransmissions, limites de file HBA, ou QoS qui bride par initiateur.
Solution : Validez l’état du multipath, vérifiez les profondeurs de file, cherchez des erreurs de lien, et confirmez qu’aucune politique QoS ne vous bride.
6) « Les volumes cloud excellent pendant 30 secondes, puis s’effondrent »
Symptôme : La première minute est géniale ; ensuite vous butez sur un mur.
Cause racine : Crédits de burst ou plafonds baseline.
Solution : Benchmarquez assez longtemps pour vider les crédits. Dimensionnez pour la baseline, pas pour le burst. Si le burst est partie de votre design, prouvez le comportement de recharge des crédits selon votre cycle d’utilisation.
Trois mini-histoires d’entreprise (anonymisées, plausibles et techniquement exactes)
Mini-histoire 1 : L’incident causé par une mauvaise hypothèse
Ils ont remplacé un lot de disques bruyants et vieillissants par un bel array qui « faisait 800k ops ». Le plan du projet avait une seule ligne performance : « nouveau stockage plus rapide que l’ancien ». C’était tout le critère d’acceptation. Il a passé un test d’une heure. Tout le monde est rentré chez soi.
Deux semaines plus tard, le traitement de fin de mois a commencé. La base de données n’était ni CPU-bound ni verrouillée. Elle était juste… lente. Les jobs batch se sont accumulés. Les latences API ont grimpé jusqu’à ce que le support client commence sa propre surveillance : « Le système est en panne ? »
L’array fournissait bien les ops promises, mais à une profondeur de file que l’application ne produisait jamais. Le caching de l’array rendait les lectures brillantes ; les écritures, sous une charge mixte avec des commits synchrones, étaient bottleneckées par une politique qu’ils n’avaient pas réalisée : l’accusé d’écriture était fixé sur un mode de protection conservateur et les petites écritures aléatoires étaient sérialisées par un chemin interne étroit.
La mauvaise hypothèse n’était pas « les vendeurs mentent ». Elle était plus subtile : l’équipe supposait qu’un seul chiffre IOPS signifiait « plus rapide en tous points », et que les politiques de protection n’avaient pas de personnalité de performance.
La correction n’a pas demandé d’héroïsme. Ils ont collecté les percentiles à une concurrence réaliste, changé le réglage de protection pour la classe de volume spécifique, et séparé le WAL/log IO sur une couche à latence plus faible. Le mois de fin a cessé d’être un sacrifice rituel.
Mini-histoire 2 : L’optimisation qui a échoué
Une équipe plateforme a essayé de « débloquer la performance » en augmentant les profondeurs de file partout. Ils ont relevé les paramètres de queue NVMe, ajusté des paramètres multipath, et encouragé les équipes à tourner avec plus d’IO en attente. Les benchmarks se sont améliorés. La présentation était belle.
Puis le trafic de production a changé de forme. Un petit nombre de locataires ont commencé à générer des rafales de lectures et écritures aléatoires en même temps que la maintenance en arrière-plan : snapshots, compactions, et un rebuild sur un nœud. Le débit semblait correct, mais la latence tail est devenue une anthologie d’horreur. Les timeouts de requêtes ont grimpé parce que les services avaient des deadlines strictes et ne pouvaient pas attendre derrière de longues files appareils.
L’échec était prévisible : ils ont optimisé pour les IOPS agrégées, pas pour les SLO de latence. Les files profondes cachaient la douleur en gardant les appareils occupés, mais les services utilisateurs ont besoin de files courtes et de réponses rapides. Un périphérique à 100% d’utilisation n’est pas « efficace » s’il transforme votre 99e percentile en rançon.
La remédiation a été de traiter la profondeur de file comme un réglage par workload. Les services sensibles à la latence ont eu une QD plus basse et une isolation plus forte. Les workloads batch ont pu utiliser les files profondes quand la plateforme avait de la marge. Ils ont aussi ajouté des contrôles IO cgroup pour empêcher les jobs d’arrière-plan « aidants » de dévorer les ressources du trafic interactif.
La partie la plus drôle a été à quel point le graphique final était ennuyeux. La latence tail s’est aplatie ; les IOPS de pic ont baissé. Tout le monde a arrêté d’être paginé à 2h du matin, ce qui est le seul KPI qui compte.
Mini-histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une autre entreprise avait une règle : chaque plateforme de stockage avait une recette de benchmark courte et versionnée. Même jobs fio, même durée, mêmes étapes de préconditionnement, mêmes cibles de remplissage. Pas d’exceptions. Les ingénieurs se plaignaient discrètement, parce que la cohérence n’est pas excitante.
Un vendredi, un nouveau lot de SSD « équivalents » est arrivé à cause d’une substitution d’approvisionnement. Le système a démarré, les workloads ont migré, et en quelques heures ils ont observé un P99 écritures légèrement plus élevé. Pas catastrophique—juste étrange. L’on-call a extrait les résultats benchmark standards de leur baseline interne et a exécuté la même suite sur un nœud isolé.
La différence était évidente : la performance d’écriture aléatoire soutenue se dégradait plus vite et la queue tail était plus épaisse. Les disques n’étaient pas cassés ; ils étaient différents. Firmware, type de NAND, comportement du cache—quelque chose avait changé.
Parce qu’ils avaient des données de baseline ennuyeuses, ils n’ont pas argumenté sur des impressions. Ils ont mis le nouveau lot en quarantaine sur une couche moins sensible à la latence, mis à jour les contraintes d’achat, et exigé une qualification pour de futures substitutions. Pas d’incident, pas d’impact client, pas de week-end perdu.
C’est souvent à cela que ressemble « l’excellence opérationnelle » : un graphique que personne ne présentera jamais, et un pager qui reste silencieux.
Listes de vérification / plan pas à pas
Checklist de bon sens pour les achats (avant de signer)
- Exigez la recette du benchmark : taille de bloc, mix rw, QD, threads, durée, préconditionnement, taille de dataset.
- Exigez la latence en percentiles : au minimum P50/P95/P99 à la charge revendiquée.
- Exigez le comportement en steady-state : 30+ minutes pour les charges orientées écriture ; incluez des graphiques si possible.
- Testez à des niveaux de remplissage réalistes : au moins 60–80% pour les pools flash si c’est ainsi que vous allez opérer.
- Spécifiez la performance en mode défaillance : impact des rebuilds/scrubs/basculement de contrôleur et temps de récupération.
- Spécifiez les exigences hôtes : CPU, génération PCIe, HBA, versions de drivers, paramètres multipath.
- Clarifiez burst vs baseline : surtout pour les volumes cloud et les arrays avec cache.
Plan d’exécution de benchmark (répétable et défendable)
- Réservez un hôte propre : désactivez cron jobs non liés, backups et agents bruyants pendant la fenêtre.
- Validez identité et santé : modèle/firmware, SMART, comportement thermique.
- Verrouillez les variables de test : même version de fio, même kernel, mêmes options de montage, même politique NUMA si possible.
- Préconditionnez quand pertinent : surtout pour les tests d’écritures soutenues.
- Lancez plusieurs profils : au moins 4K randread, 4K randwrite, mix 70/30, et un test de débit séquentiel.
- Enregistrez percentiles et séries temporelles : pas seulement des résumés ; répétez les runs.
- Comparez à votre SLO : acceptez/rejetez sur la base de la latence au débit requis, pas sur les IOPS de pic.
Checklist d’acceptation en production (après déploiement)
- Établissez des baselines : snapshots iostat/fio sous conditions connues comme bonnes.
- Instrumentez la latence : collectez P95/P99 au niveau hôte et application.
- Testez un mode défaillance : coupez un chemin, déclenchez un basculement contrôlé, ou simulez une fenêtre de rebuild.
- Validez l’isolation : assurez-vous que les jobs batch ne peuvent pas affamer les workloads interactifs.
FAQ
Q1: Les IOPS sont-ils inutiles ?
Non. Elles sont juste incomplètes. Les IOPS sont utiles quand elles sont accompagnées de la taille de bloc, de la profondeur de file, du mix lecture/écriture, et des percentiles de latence. Sinon c’est un chiffre qui aide quelqu’un à gagner une réunion.
Q2: Quelle est une profondeur de file raisonnable pour benchmarker ?
Benchmarquez la profondeur de file que votre workload produit. Si vous ne la connaissez pas, mesurez-la indirectement via les IO en attente observés et le comportement de latence. Pour beaucoup de services sensibles à la latence, une QD entre 1 et 32 par périphérique est plus représentative que 128+.
Q3: Pourquoi les vendeurs utilisent-ils toujours le 4K random read ?
Parce que cela produit un nombre d’opérations grand et impressionnant, et c’est un pattern légitime pour certaines charges. Ce n’est toutefois pas un proxy universel pour « stockage rapide ».
Q4: Combien de temps devrais-je lancer fio ?
Assez longtemps pour voir le steady state et le comportement tail. Pour les lectures, quelques minutes peuvent suffire si l’ensemble de données dépasse le cache. Pour les écritures soutenues, 30 minutes est un meilleur point de départ, et des durées plus longues sont souvent justifiées.
Q5: Dois-je benchmarker sur des périphériques blocs bruts ou des fichiers ?
Si vous voulez la capacité du device, utilisez le brut. Si vous voulez « ce que mon application obtient », benchmarquez via la même pile système de fichiers que vous utiliserez en production. Les deux sont valides ; les mélanger sans le dire est la source de longues disputes.
Q6: Pourquoi la performance chute quand le disque est plus plein ?
Les couches de traduction flash ont besoin de blocs libres pour gérer efficacement les écritures. À mesure que l’espace libre diminue, le coût de la garbage collection augmente et l’amplification d’écriture monte. Beaucoup de systèmes sont excellents à 5–10% de remplissage et très différents à 70–90%.
Q7: Qu’en est-il du « FPS » d’un benchmark applicatif au lieu de fio ?
Les benchmarks applicatifs sont meilleurs pour le dimensionnement bout-en-bout—s’ils reflètent votre pattern d’accès et la concurrence. Mais ils peuvent aussi être manipulés avec des caches, des datasets irréalistes, ou des réglages de durabilité désactivés. Traitez-les avec la même scepticisme : exigez la recette et les percentiles.
Q8: Comment comparer NVMe local vs SAN vs stockage bloc cloud ?
Comparez les percentiles de latence au débit requis, et incluez le comportement en cas de défaillance. Le SAN et le cloud ajoutent souvent de la latence de chemin et de la variabilité. Le NVMe local est habituellement de plus faible latence mais moins partagé et peut avoir des risques opérationnels différents (remplacement, mirroring, panne de nœud).
Q9: Puis-je faire confiance à un run de benchmark dans une VM ?
Vous pouvez, si vous comprenez la couche de virtualisation : files hôte partagées, politiques de throttling, et noisy neighbors peuvent dominer les résultats. Pour la planification de capacité, testez dans le même environnement où vous exécuterez. Pour la qualification du device, testez en bare metal ou avec isolation stricte.
Q10: Quel est le critère d’acceptation le plus simple qui ne soit pas stupide ?
Choisissez un profil de workload représentatif et exigez P99 latence sous X ms à Y IOPS/MB/s pendant au moins Z minutes, avec un dataset plus grand que le cache et des réglages de durabilité identiques à la production.
Conclusion : étapes pratiques suivantes
Si vous ne retenez que trois actions, faites celles-ci :
- Refusez les revendications de performance à un chiffre. Demandez la recette complète et les percentiles de latence.
- Benchmarquez comme vous opérez. Profondeur de file réaliste, mix réaliste, taille de dataset réaliste, durée réaliste.
- Dimensionnez selon vos SLO, pas selon un titre. Achetez « P99 sous charge », pas du « jusqu’à » n’importe quoi.
Puis faites la chose peu glamour qui vous fera paraître compétent plus tard : consignez vos fichiers job de benchmark, conservez les sorties de baseline, et relancez-les après les changements. Quand le prochain « mais la brochure dit… » arrivera, vous aurez des données, pas des opinions.