Vous avez un pool ZFS qui affiche de bons benchmarks l’après-midi et qui se transforme en citrouille à 2 h du matin.
Les scrubs s’éternisent. La latence bondit. La base de données commence à dépasser les délais, et tout le monde fixe « %util » comme s’il allait avouer quelque chose.
Quelque part dans la pile, l’ordonnanceur IO Linux vous aide… ou aggrave poliment la situation.
En bref : avec ZFS, on ne « règle » pas tant l’ordonnanceur que l’on l’empêche de se battre contre le reste du système.
C’est un article de décision : quoi définir pour HDD, SATA/SAS SSD et NVMe ; comment le prouver avec des commandes ; et comment diagnostiquer
les modes de panne désagréables quand la réalité contredit vos hypothèses.
La règle en une phrase (que définir)
Si vous voulez un réglage par défaut qui tient en production : utilisez mq-deadline pour les disques rotatifs et la plupart des SATA/SAS SSD,
et utilisez none pour les NVMe (et autres périphériques haut de gamme avec leurs propres files profondes matérielles).
C’est la ligne de base. N’en déviez que si vous pouvez expliquer, avec des mesures, ce que vous optimisez : latence de queue, équité entre tâches,
ou une quirk spécifique du périphérique/driver.
Ce que font réellement les ordonnanceurs IO Linux sous blk-mq
L’ordonnanceur IO n’est pas « un interrupteur de mode performance ». C’est un moteur de politique situé entre la couche bloc et le pilote du périphérique,
décidant comment les requêtes sont ordonnées, fusionnées et dispatchées. Sur Linux moderne, la plupart des périphériques bloc utilisent la couche multi-file d’attente (blk-mq),
ce qui change l’histoire des ordonnanceurs comparé à l’ère mono-file.
blk-mq a changé le problème : d’un ascenseur à plusieurs voies
Les ordonnanceurs « ascenseur » classiques (deadline, CFQ, noop) étaient conçus pour une file unique de requêtes alimentant une file matérielle unique.
blk-mq ajoute de multiples files de soumission logicielles (souvent par CPU) mappées à une ou plusieurs files de dispatch matérielles. L’ordonnanceur peut maintenant s’exécuter
par contexte matériel, et le périphérique lui‑même peut faire un réordonnancement agressif (NVMe est particulièrement performant à ce jeu).
En pratique : si le matériel réalise déjà un queueing profond et un dispatch intelligent, ajouter une autre couche d’astuce logicielle peut
augmenter la variance de latence et la charge CPU sans améliorer le débit.
mq-deadline : attente bornée et « ne pas affamer les lectures »
mq-deadline est la version blk-mq de deadline. Il garde des files séparées pour lecture et écriture, suit des temps d’expiration,
et dispatch les requêtes de façon à éviter l’affamement. Il effectue aussi la fusion des requêtes quand c’est possible.
Sur les supports rotatifs, cela compte. Les HDD ont une latence aléatoire catastrophique ; si vous laissez les écritures se mettre en file indéfiniment, les lectures peuvent être affamées et votre application
l’interprétera comme « le stockage est mort ». Deadline tente de limiter ces dégâts. Sur les SATA SSD, il peut encore aider en lissant les rafales et en empêchant
la latence de devenir incontrôlable sous des charges mixtes.
none : « mains libres » (mais pas « pas de mise en file »)
none signifie que la couche bloc effectue un ordonnancement minimal au-delà de ce que blk-mq fait intrinsèquement. Les requêtes continuent à se mettre en file — simplement sans
politique d’ascenseur supplémentaire. C’est généralement le meilleur choix pour NVMe car :
- Les périphériques NVMe ont plusieurs files matérielles et des ordonnanceurs internes sophistiqués.
- NVMe prospère grâce au parallélisme ; un ordre logiciel supplémentaire peut réduire la concurrence.
- La charge CPU compte à haut IOPS ; « none » réduit le travail de l’ordonnanceur.
Pourquoi pas BFQ, kyber ou « ce que la valeur par défaut propose » ?
BFQ et kyber existent pour de bonnes raisons. BFQ peut être excellent pour l’interactivité desktop et l’équité ; kyber vise le contrôle de latence sous charge.
Mais ZFS a déjà ses propres patterns IO et comportements de buffering, et de nombreux workloads ZFS en production se préoccupent davantage de la latence tail prévisible
et d’éviter des interactions pathologiques que de l’équité par cgroup au niveau bloc.
Si vous exécutez des hôtes multi-tenant avec des exigences strictes d’équité, vous pouvez les explorer. Mais pour le scénario courant « pool ZFS pour bases de données,
VMs, NFS, stockage d’objets ou sauvegardes », mq-deadline/none sont de bons points de départ. La plupart du temps, la bonne action n’est pas « un meilleur ordonnanceur »,
c’est « arrêter le double-ordonnancement et mesurer correctement la latence ».
Comment ZFS change la donne (ARC, TXG, sync, et pourquoi « plus d’ordonnancement » n’est pas mieux)
ZFS n’est pas un consommateur de bloc stupide. C’est un système de fichiers et un gestionnaire de volumes qui fait déjà de l’agrégation, de l’ordonnancement et du façonnage d’écritures.
Quand on dit « ZFS aime les écritures séquentielles », on veut dire : ZFS s’efforce de transformer des écritures d’application dispersées en IOs plus larges et contiguës au moment du commit.
Les écritures ZFS sont mises en attente : le battement TXG
ZFS regroupe les modifications en transaction groups (TXGs). Les données sales s’accumulent en mémoire, puis ZFS les commet sur disque. Ce batching est
excellent pour le débit et la compression, et c’est aussi pourquoi « mon application a écrit 4 Ko mais le disque a fait 1 Mo » n’est pas un mystère — c’est ZFS qui optimise.
L’ordonnanceur IO voit le schéma final des IO blocs, pas l’intention de votre application. Si vous ajoutez un réordonnancement agressif au niveau ordonnanceur,
vous pouvez interférer avec la tentative de ZFS de gérer la latence pour les lectures tout en vidant les écritures.
Écritures synchrones : où les hypothèses meurent
Pour les écritures sync, ZFS doit garantir la durabilité avant d’acquitter la complétion (selon les réglages et le workload). Si vous n’avez pas de SLOG approprié
(separate intent log), votre workload synchrone peut devenir « la latence d’écriture aléatoire est votre nouvelle identité ».
Aucun ordonnanceur IO ne vous sauvera d’un pool de HDD effectuant de petites écritures synchrones sans dispositif de log. Il peut seulement façonner l’intensité de l’attente.
Comportement de lecture ZFS : prefetch et métadonnées
ZFS fait du prefetch et du caching adaptatif (ARC). Les lectures sont souvent servies depuis la RAM ; les lectures qui atteignent le disque peuvent être riches en métadonnées, aléatoires,
ou provoquées par scrub/resilver. Cela signifie que votre « choix d’ordonnanceur » devrait prioriser la prévention des explosions de latence tail quand le disque est occupé.
Double mise en file et « taxe de latence »
ZFS met les IO en file en interne. La couche bloc met les IO en file. Le firmware du périphérique met les IO en file. Ce sont trois endroits où la latence peut se cacher, et elle adore
se multiplier sous pression.
Si votre périphérique est un NVMe avec des files profondes, ajouter mq-deadline peut augmenter la variance de latence en remélangeant des requêtes que le contrôleur aurait
pu mieux gérer en parallèle. Si votre périphérique est un HDD, le laisser en « none » peut permettre des patrons pathologiques d’affamement que ZFS seul
ne peut pas toujours lisser.
Idée paraphrasée (Werner Vogels, fiabilité/opérations) : « Tout finit par tomber en panne ; vous concevez des systèmes en partant de cette hypothèse. »
La sélection d’un ordonnanceur reflète exactement cet état d’esprit : choisissez la politique qui échoue le moins mal sous une charge désagréable.
Recommandations selon le support : HDD vs SATA/SAS SSD vs NVMe
HDD rotatif (disques simples, miroirs, RAIDZ)
Utilisez mq-deadline.
Les HDD sont des machines à latence avec un hobby secondaire : faire des IO. Sur des workloads mixtes (scrub + lectures + écritures), un HDD peut affamer les lectures pendant qu’il
mâche des écritures. mq-deadline vous donne une garantie pratique : les lectures ne resteront pas bloquées derrière les écritures indéfiniment.
Quand envisager autre chose ? Principalement si vous avez un appliance spécialisé ou si vous avez validé qu’un autre ordonnanceur (comme kyber)
donne une meilleure latence tail sur votre charge exacte. Mais pour ZFS sur Linux avec vdevs HDD, mq-deadline est la réponse ennuyeuse mais correcte.
SATA/SAS SSD (grand public ou entreprise)
Par défaut, mq-deadline, puis envisagez none seulement si vous avez des preuves que cela aide et que le SSD ne se comporte pas mal.
Les SATA/SAS SSD varient énormément. Certains ont un ordonnancement interne correct ; d’autres s’effondrent de façon étrange pendant la garbage collection ou lorsque la politique du cache d’écriture interagit
avec la protection contre les pertes de courant (ou son absence).
mq-deadline garde souvent la latence plus prévisible sur les SATA SSD sous des charges mixtes lecture/écriture ou lors d’un comportement de flush en rafales, ce qui correspond bien aux flush TXG de ZFS.
« none » peut aussi convenir — surtout sur des SSD entreprise au firmware robuste — mais ne supposez pas que les règles NVMe s’appliquent automatiquement.
NVMe (PCIe)
Utilisez none.
NVMe est conçu pour des files parallèles, pas pour être traité comme un disque SATA sophistiqué. Le contrôleur prend déjà des décisions de dispatch en matériel.
Votre travail est de garder le chemin logiciel léger et d’éviter de sérialiser ce qui devrait être concurrent.
Si vous faites tourner mq-deadline sur NVMe et que vous observez une pire latence tail ou un débit réduit, ce n’est pas surprenant ; c’est le logiciel qui tente de devancer
un périphérique conçu précisément pour éviter cela.
Périphériques bloc virtualisés ou SAN
C’est là que vous arrêtez de vous fier aux étiquettes. Un « disque » peut être un périphérique bloc virtuel reposant sur un réseau, un contrôleur RAID, ou une baie de stockage avec
son propre cache et ses files. Dans ces cas :
- Si le périphérique se présente comme rotatif mais est en fait soutenu par de la flash, votre choix peut différer.
- Si l’hyperviseur ou la baie effectue déjà un fort ordonnancement, « none » peut être meilleur.
- Si vous avez besoin d’équité entre plusieurs invités, un ordonnanceur qui modèle la latence peut aider — mais validez.
Pour de nombreux disques virtuels, vous finirez souvent avec mq-deadline comme valeur sûre, à moins que le fournisseur ne recommande explicitement « none » et que vous l’ayez prouvé.
Faits et contexte historique intéressants (pour comprendre les valeurs par défaut)
- L’ordonnanceur original « deadline » a été conçu pour éviter l’affamement — un vrai problème quand le writeback pouvait enterrer les lectures sur des disques lents.
- CFQ était autrefois la valeur par défaut sur beaucoup de distributions parce qu’il améliorait la réactivité desktop, pas parce qu’il maximisait le débit serveur.
- blk-mq est arrivé pour scaler l’IO sur systèmes multicœurs ; le chemin mono-file ancien devenait un goulot à haut IOPS.
- « noop » était historiquement recommandé pour les contrôleurs RAID car le contrôleur gérait son propre ordonnancement ; « none » est l’équivalent à l’ère blk-mq.
- NVMe a été conçu autour de multiples files de soumission et complétion, explicitement pour réduire la contention sur les verrous et améliorer le parallélisme.
- Le journal d’intention de ZFS (ZIL) existe à cause des sémantiques sync POSIX ; ce n’est pas une fonction de performance, c’est une fonction de correction avec des conséquences de performance.
- ZFS sur Linux (OpenZFS) a mûri plus tard que Solaris ZFS ; les interactions spécifiques à Linux (comme les ordonnanceurs blk-mq) sont devenues un sujet de tuning après la maturité du port.
- « IOPS » est devenu un métrique grand public avec la flash ; à l’ère HDD, on parlait surtout de débit parce que la latence était uniformément mauvaise.
- Les noyaux modernes ont changé les valeurs par défaut plusieurs fois ; si vous appliquez bêtement des conseils de 2016, vous choisissez probablement pour un noyau qui n’existe plus.
Playbook de diagnostic rapide : trouver le goulot sans deviner
Vous êtes réveillé par une alerte. La latence augmente. Le pool ZFS « semble correct » parce qu’il ne crie pas ; il ruine juste discrètement votre journée. Voici le chemin le plus court
vers la vérité.
Premier point : identifiez la classe de périphérique et l’ordonnanceur courant
- Est‑ce un HDD, un SATA SSD ou un NVMe ?
- L’ordonnanceur est‑il réellement ce que vous pensez ?
- Est‑ce que vous benchmarkez le pool ou un seul membre de vdev par accident ?
Deuxième point : déterminez si vous êtes lié par la latence ou le débit
- Vérifiez par‑périphérique await, équivalents svctm (avec prudence), et profondeur de file.
- Regardez les symptômes de latence tail : timeouts applicatifs, blocages d’écriture sync, hoquets NFS.
Troisième point : séparez « ZFS est en train de vider » de « le disque est lent »
- Vérifiez le comportement TXG et des données sales (indirectement via les stats ZFS et les patterns de workload).
- Vérifiez si les écritures sync sont en cause (et si vous avez un SLOG efficace).
Quatrième point : cherchez les saboteurs habituels
- Un seul disque mourant dans un vdev provoquant des retries et timeouts.
- Des HDD SMR se faisant passer pour des disques normaux.
- Un SSD grand public sans protection contre les pertes de courant puni par les sémantiques sync.
- Gestion d’énergie PCIe/NVMe ou anomalies de firmware.
Cinquième point : ne changez l’ordonnanceur qu’ensuite
Les changements d’ordonnanceur sont peu risqués comparés, par exemple, à changer le recordsize sur un dataset occupé — mais ils ont aussi un impact moindre
comparé à corriger la conception des écritures sync ou remplacer un disque défectueux. Changez l’ordonnanceur quand vous pouvez articuler le mode de défaillance qu’il adresse :
affamement et équité (mq-deadline) vs réduction de l’overhead et meilleur parallélisme (none).
Tâches pratiques (commandes, sorties et décisions)
Ce sont des tâches réelles que vous pouvez exécuter sur un hôte Linux avec ZFS. Chacune inclut : la commande, un exemple de ce que vous pourriez voir, ce que cela signifie, et
la décision à prendre. Faites-les dans cet ordre lorsque vous diagnostiquer un système que vous n’avez pas construit.
Tâche 1 : lister les périphériques bloc et repérer NVMe vs SATA
cr0x@server:~$ lsblk -d -o NAME,ROTA,TRAN,MODEL,SIZE
NAME ROTA TRAN MODEL SIZE
sda 1 sata ST12000NM0008-2JH101 10.9T
sdb 1 sata ST12000NM0008-2JH101 10.9T
sdc 0 sata Samsung SSD 870 EVO 931.5G
nvme0n1 0 nvme Samsung SSD 980 PRO 953.9G
Sens : ROTA=1 indique rotatif (HDD). TRAN=nvme indique NVMe. Les SATA SSD affichent ROTA=0 et TRAN=sata.
Décision : Mettez les HDD sur mq-deadline. Mettez les NVMe sur none. Pour un SATA SSD, commencez par mq-deadline sauf raison contraire.
Tâche 2 : vérifier l’ordonnanceur courant par périphérique
cr0x@server:~$ for d in sda sdb sdc nvme0n1; do echo -n "$d: "; cat /sys/block/$d/queue/scheduler; done
sda: [mq-deadline] none
sdb: [mq-deadline] none
sdc: mq-deadline [none]
nvme0n1: [none]
Sens : L’ordonnanceur entre crochets est actif. Ici, le SATA SSD (sdc) est sur none ; les HDD sont sur mq-deadline ; NVMe est sur none.
Décision : Si ce SATA SSD est un SLOG ou un vdev spécial et que vous observez des pics de latence, envisagez de le passer à mq-deadline et mesurez.
Tâche 3 : vérifier si le noyau propose bien les ordonnanceurs attendus
cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none
Sens : Sur certains systèmes, vous verrez des options supplémentaires comme kyber ou bfq. Si elles ne sont pas présentes, vous ne pouvez pas les sélectionner.
Décision : Ne perdez pas de temps à chasser un ordonnanceur mentionné dans un blog si votre noyau ne le supporte pas. Tenez‑vous à mq-deadline/none et corrigez le vrai goulot.
Tâche 4 : vérifier quels périphériques appartiennent à quels vdevs ZFS
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-ST12000NM0008_1 ONLINE 0 0 0
ata-ST12000NM0008_2 ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
ata-ST12000NM0008_3 ONLINE 0 0 0
ata-ST12000NM0008_4 ONLINE 0 0 0
logs
nvme-Samsung_SSD_980PRO ONLINE 0 0 0
Sens : ZFS est construit à partir de vdevs. Les performances et les modes de panne dépendent souvent d’un membre lent ou malsain.
Décision : Appliquez les changements d’ordonnanceur aux périphériques bloc sous-jacents qui correspondent aux membres de vdev — en particulier logs et special vdevs.
Tâche 5 : surveiller la latence et le débit au niveau ZFS pendant la charge
cr0x@server:~$ zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 5.12T 16.7T 180 620 21.3M 78.4M
mirror-0 2.55T 8.35T 90 310 10.6M 39.2M
mirror-1 2.57T 8.33T 90 310 10.7M 39.2M
logs - - 0 250 0 12.1M
Sens : Vous pouvez voir si le périphérique de log est fortement utilisé (workload sync), et si les opérations lecture/écriture sont équilibrées entre les miroirs.
Décision : Si le log est occupé et que la latence est mauvaise, les changements d’ordonnanceur sur le périphérique de log peuvent affecter la latence tail — surtout s’il s’agit d’un SATA SSD.
Tâche 6 : identifier la latence IO et la saturation par périphérique (iostat)
cr0x@server:~$ iostat -x -d 1
Device r/s w/s r_await w_await aqu-sz %util
sda 2.1 78.3 18.2 145.7 9.84 99.0
sdb 1.9 77.5 17.9 141.2 9.53 98.7
nvme0n1 0.0 250.2 0.2 1.8 0.45 12.3
Sens : Les HDD sont saturés (%util ~99) avec un énorme w_await. Le log NVMe semble correct. Votre goulot est les vdevs HDD, pas l’ordonnanceur sur NVMe.
Décision : Si les lectures expirent, mq-deadline sur les HDD est approprié ; si c’est déjà en place, votre prochaine action est le façonnage du workload (sync, recordsize, layout de vdev) ou ajouter des plateaux.
Tâche 7 : confirmer que le flag rotational est cohérent (il ment parfois)
cr0x@server:~$ cat /sys/block/sdc/queue/rotational
0
Sens : 0 signifie non rotatif. Pour certains contrôleurs RAID ou périphériques virtuels, cela peut être trompeur.
Décision : Si un « disque virtuel » est en réalité soutenu par des HDD et affirme rotational=0, ne mettez pas none aveuglément. Validez avec le comportement de latence et les contraintes du fournisseur.
Tâche 8 : vérifier la profondeur de file du périphérique et voir si vous limitez NVMe par erreur
cr0x@server:~$ cat /sys/block/nvme0n1/queue/nr_requests
1023
Sens : C’est la taille de la file de requêtes. Une valeur trop basse peut limiter le débit ; trop haute peut augmenter la latence sous certaines charges.
Décision : Ne la touchez pas sauf si vous avez un problème de mise en file mesuré. Le choix d’ordonnanceur suffit généralement à ce niveau ; les gros réglages ont des effets secondaires plus importants.
Tâche 9 : changer temporairement l’ordonnanceur (runtime) pour un périphérique
cr0x@server:~$ echo mq-deadline | sudo tee /sys/block/sdc/queue/scheduler
mq-deadline
Sens : Cela change l’ordonnanceur jusqu’au reboot (ou jusqu’à ce qu’une règle udev le remplace).
Décision : Utilisez ceci pour des tests contrôlés pendant une fenêtre de maintenance. Mesurez avant/après avec iostat et la latence applicative, pas au pif.
Tâche 10 : confirmer que le changement a « pris »
cr0x@server:~$ cat /sys/block/sdc/queue/scheduler
[mq-deadline] none
Sens : Il est actif maintenant.
Décision : Si les performances s’améliorent mais reviennent après reboot, il faut persister le changement (tâche suivante).
Tâche 11 : rendre l’ordonnanceur persistant avec une règle udev
cr0x@server:~$ sudo bash -c 'cat > /etc/udev/rules.d/60-io-scheduler.rules <
cr0x@server:~$ sudo udevadm control --reload-rules
cr0x@server:~$ sudo udevadm trigger --type=devices --action=change
Sens : Cela applique une politique d’ordonnanceur selon le type de périphérique. Ce n’est pas élégant, mais ça marche.
Décision : Si vous gérez des flottes, encodez cela dans la gestion de configuration et traitez‑le comme toute autre baseline : revu, testé et déployé progressivement.
Tâche 12 : vérifier qu’udev a appliqué la règle après trigger
cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none]
Sens : Bien : HDD en mq-deadline, NVMe en none.
Décision : Passez à la validation du workload. La politique d’ordonnanceur est un moyen, pas une fin.
Tâche 13 : détecter un workload synchrone intensif (indicateur rapide)
cr0x@server:~$ zfs get -o name,property,value -H sync tank
tank sync standard
Sens : sync=standard respecte le comportement sync de l’application. Si votre application utilise beaucoup fsync, le périphérique de log est important.
Décision : Ne mettez pas sync=disabled comme « correctif de performance » sauf si vous acceptez la perte de données. Certaines carrières se terminent de cette façon.
Tâche 14 : mesurer la latence réelle avec fio contre un ZVOL ou dataset (prudemment)
cr0x@server:~$ sudo fio --name=randread --filename=/tank/testfile --size=4G --rw=randread --bs=4k --iodepth=32 --numjobs=4 --direct=1 --time_based --runtime=30
randread: (groupid=0, jobs=4): err= 0: pid=22110: Fri Dec 25 02:10:11 2025
read: IOPS=58.2k, BW=227MiB/s (238MB/s)(6815MiB/30002msec)
clat (usec): min=90, max=9210, avg=265.4, stdev=112.7
lat (usec): min=92, max=9220, avg=267.2, stdev=112.9
Sens : Vous obtenez la distribution de latence, pas seulement le débit. La latence max vous parle du comportement tail.
Décision : Si passer de mq-deadline à none change la moyenne mais aggrave le max (ou vice versa), décidez selon la sensibilité applicative. Les bases de données détestent la latence tail plus que perdre 5 % de débit.
Blague #1 : Si vous changez les ordonnanceurs IO sans mesurer la latence, vous ne faites pas du tuning — vous faites de l’astrologie du stockage.
Trois mini-récits du monde de l’entreprise basés sur des cas réels
Mini-récit 1 : L’incident causé par une fausse hypothèse (NVMe « a besoin » de mq-deadline)
Une entreprise de taille moyenne exploitait un cluster de virtualisation multi-tenant sur OpenZFS. Ils ont renouvelé le matériel, remplacé par des NVMe plus récents,
et gardé leur ancien playbook de tuning. Ce playbook disait : « deadline réduit la latence », donc ils ont mis mq-deadline partout.
Le changement semblait inoffensif. La première semaine était calme. Puis le lundi matin de grande activité est arrivé : pics de boot de VM, ingestion de sauvegardes, et un basculement de base de données.
Soudain, ils ont observé un comportement étrange : le débit semblait correct, mais la latence au 99e percentile a fortement augmenté au point de provoquer des timeouts applicatifs.
Les invités ne « ralentissaient » pas. Ils se bloquaient. La différence est importante.
L’équipe a d’abord cherché dans les réglages ZFS. Ils ont essayé d’ajuster recordsize sur quelques datasets, puis débattu de l’usure du SLOG, puis blâmé l’hyperviseur.
Pendant ce temps, le vrai indice était sous leurs yeux : l’utilisation CPU en softirq et dans les chemins de la couche bloc grimpait, et la latence de complétion IO devenait plus variable
sous concurrence.
Ils ont basculé NVMe sur none sur deux hôtes canaris et relancé la même charge mixte. La latence tail s’est améliorée ; la charge CPU a diminué ; les blocages ont disparu.
L’ancienne hypothèse — « deadline réduit toujours la latence » — était vraie à l’époque des HDD et parfois pour SATA SSD. Pour NVMe, c’était une taxe sans bénéfice.
La leçon n’était pas « mq-deadline est mauvais ». La leçon était « adaptez la politique au périphérique ». NVMe veut du parallélisme, pas qu’on lui tienne la main.
Mini-récit 2 : L’optimisation qui s’est retournée contre l’équipe (mettre none sur HDD pour « laisser ZFS gérer »)
Une autre organisation gérait un grand dépôt de sauvegardes sur ZFS avec de larges vdevs RAIDZ composés de HDD. Ils avaient lu que ZFS agrège déjà les écritures,
et ont conclu que l’ordonnanceur était redondant. Quelqu’un a mis tous les disques en none, a ajouté la règle udev, et a passé à autre chose.
Le débit en régime stable pendant l’ingestion nocturne s’est effectivement amélioré un peu. Les félicitations ont fusé, ce qui est généralement le moment choisi par le système pour prévoir sa vengeance.
La fenêtre de scrub suivante a été le premier vrai test : lectures de scrub plus écritures en cours plus quelques restaurations.
Les jobs de restauration (lectures) sont devenus douloureusement lents. Pas « un peu plus lent », mais « les utilisateurs pensent que la restauration est bloquée ». La latence a flambé pendant les périodes d’écriture intense.
Le pool ne tombait pas en panne ; il prenait juste un temps impressionnant à décider de faire des lectures.
La cause racine était classique : les HDD sous workload mixte peuvent affamer les lectures derrière les écritures si vous n’appliquez pas un peu d’équité.
L’ordonnancement interne de ZFS ne peut pas toujours compenser quand l’ordre de dispatch de la couche bloc est effectivement « peu importe, dans l’ordre d’arrivée ».
Remettre les HDD en mq-deadline a restauré un comportement de lecture prévisible pendant les scrubs et les IO mixtes. Le débit pendant l’ingestion a légèrement diminué,
mais les restaurations sont redevenues fiables. L’entreprise n’a pas payé pour « débit max à 2 h du matin ». Elle a payé pour des restaurations qui finissent avant la réunion.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la situation (baselines par périphérique + canaris)
Un service financier avait pour habitude : chaque mise à jour de noyau passait par des canaris de stockage. Rien de chic. Deux hôtes par génération matérielle,
même workload rejoué, mêmes dashboards. Ils tenaient un petit document de baseline : types de périphériques, versions de firmware, réglages d’ordonnanceur, et bandes de latence attendues.
Un trimestre, une mise à jour routinière du noyau a changé le comportement sur un sous-ensemble de SATA SSD utilisés comme special vdevs. Rien de catastrophique — juste une dérive lente de la latence tail.
Les canaris l’ont détecté parce qu’ils regardaient le 99e percentile, pas seulement le débit moyen. Ils ont aussi remarqué que les périphériques passaient plus de temps en housekeeping interne sous écritures mixtes.
La correction n’a pas été une refonte héroïque. Ils ont standardisé ces SATA SSD sur mq-deadline, vérifié que les règles udev étaient appliquées de façon cohérente,
et l’ont déployé progressivement en surveillant la latence. Ce n’était pas excitant. C’était correct.
Plus tard, lorsqu’un incident réel est survenu — une mise à jour de firmware SSD provoquant de brefs blocages — l’équipe avait la discipline nécessaire pour tester les changements d’abord sur les canaris.
La baseline d’ordonnanceur signifiait qu’ils ne déboguaient pas dix variables à la fois.
Les pratiques ennuyeuses ne récoltent pas de crédit jusqu’à ce qu’elles évitent un type d’excitation extrêmement coûteux.
Blague #2 : L’ordonnanceur IO, c’est comme la politique de bureau — l’ignorer cause des ennuis, mais s’y impliquer trop peut aussi ruiner votre semaine.
Erreurs courantes : symptôme → cause racine → correctif
1) « NVMe est rapide mais mon pool ZFS se bloque sous charge »
Symptôme : Bon débit moyen, mais falaises de latence périodiques ; CPU noyau en hausse ; timeouts applicatifs.
Cause racine : NVMe fonctionne avec un ordonnanceur qui ajoute de l’overhead ou réduit la concurrence (souvent mq-deadline), combiné à un queueing profond sous IO mixte.
Correctif : Passez NVMe à none, validez avec des mesures de latence tail (fio + métriques applicatives), et assurez-vous de ne pas brider la profondeur de file ailleurs.
2) « Le débit du pool HDD est correct mais les lectures deviennent inutilisables pendant les sauvegardes ou scrubs »
Symptôme : Jobs de restauration/lecture rampent pendant les périodes d’écriture ; lectures interactives bloquées.
Cause racine : HDD en none (ou dispatch trop permissif), permettant aux rafales d’écriture d’affamer les lectures.
Correctif : Utilisez mq-deadline sur les membres vdev HDD. Si c’est encore mauvais, séparez les workloads, ajoutez des plateaux, ou reshaper le layout de vdev.
3) « Passer à none a amélioré les benchmarks, mais la production s’est empirée »
Symptôme : fio montre des IOPS supérieurs, mais les workloads réels affichent une pire latence p99 ou plus de jitter.
Cause racine : Les benchmarks mesuraient des workloads centrés sur le débit ; la production est sensible à la latence tail et mixte.
Correctif : Benchmarquez ce que vous exécutez. Suivez les percentiles de latence. Choisissez l’ordonnanceur d’après p95/p99, pas des captures d’écran d’IOPS max.
4) « Les réglages d’ordonnanceur ne persistent pas après reboot »
Symptôme : Vous echo vers sysfs, ça fonctionne, reboot réinitialise.
Cause racine : Les changements sysfs sont runtime seulement ; udev ou les valeurs par défaut de la distro réappliquent au démarrage.
Correctif : Utilisez une règle udev (comme montré) ou un mécanisme de tuning supporté par la distribution ; vérifiez après le boot.
5) « Un disque est lent et empoisonne tout le vdev »
Symptôme : Performance du miroir/RAIDZ s’effondre ; iostat montre un périphérique avec un await massif et des erreurs/retries.
Cause racine : Disque défaillant, câble défectueux, problème de contrôleur ou bug de firmware ; l’ordonnanceur ne réparera pas des retries matérielles.
Correctif : Confirmez avec SMART/NVMe logs ; remplacez le matériel. Gardez l’ordonnanceur sain, mais ne le traitez pas comme un outil de réparation.
6) « On a ‘réparé’ la latence sync en désactivant sync et maintenant on est courageux »
Symptôme : La latence s’améliore de façon spectaculaire ; puis vous perdez l’alimentation et vous avez du mal à expliquer les données manquantes.
Cause racine : Correction échangée contre vitesse ; ZFS faisait la bonne chose avant.
Correctif : Utilisez un SLOG propre avec protection contre les pertes de courant pour les workloads sync-intensifs ; gardez sync=standard sauf si vous acceptez délibérément la perte de données.
Listes de contrôle / plan étape par étape (adapté au changement)
Checklist A : choisir l’ordonnanceur par périphérique
- Inventaire des périphériques :
lsblk -d -o NAME,ROTA,TRAN,MODEL,SIZE. - Mapper les périphériques aux vdevs :
zpool status -v. - Définir la baseline :
- HDD : mq-deadline
- SATA/SAS SSD : mq-deadline (commencez ici)
- NVMe : none
- Si vous devez dévier, notez le métrique que vous optimisez (latence p99, débit, équité).
Checklist B : appliquer les changements en toute sécurité
- Choisissez un hôte canari (ou un membre de vdev seulement, si le risque est faible et que la redondance existe).
- Enregistrez les métriques de base :
zpool iostat -v 1,iostat -x 1, latence applicative p95/p99. - Changez l’ordonnanceur au runtime via sysfs.
- Exécutez le workload qui compte (pas seulement un benchmark synthétique).
- Comparez la latence tail et la charge CPU.
- Créez des règles udev persistantes et déployez progressivement seulement si tout est OK.
Checklist C : valider que le comportement ZFS n’a pas empiré
- Performances de scrub/resilver : est‑ce que ça affame les lectures de production ?
- Latence des écritures sync : s’est‑elle améliorée ou empirée, et le SLOG est‑il sain ?
- Compteurs d’erreurs et retries : un disque soudainement « lent » après le changement est probablement défectueux.
FAQ
1) Dois‑je toujours utiliser mq-deadline avec ZFS ?
Non. Utilisez mq-deadline pour les HDD et généralement les SATA/SAS SSD. Pour NVMe, utilisez none sauf si vous avez une raison mesurée d’agir autrement.
ZFS bénéficie d’une latence prévisible sur les supports lents ; NVMe bénéficie d’une interférence logicielle minimale.
2) Pourquoi « none » est‑il parfois plus rapide en benchmark ?
Parce que cela supprime l’overhead d’ordonnancement et préserve le parallélisme. Sur NVMe en particulier, « none » garde le chemin logiciel léger,
laissant le contrôleur faire ce pour quoi il a été conçu.
3) Si ZFS ordonne déjà les IO, pourquoi ai‑je besoin d’un ordonnanceur bloc ?
Vous n’en avez pas toujours « besoin ». Mais pour les HDD, l’équité et la prévention de l’affamement offertes par l’ordonnanceur restent utiles.
ZFS ne peut pas entièrement compenser les réalités mécaniques des supports rotatifs quand l’ordre de dispatch de la couche bloc est défavorable.
4) Qu’en est‑il de kyber ?
kyber peut être bon pour le contrôle de latence sur certains périphériques. S’il est disponible dans votre noyau et que vous avez un problème de latence spécifique que mq-deadline n’adresse pas,
cela peut valoir la peine de tester. Ne le déployez pas massivement parce qu’un fil de forum avait un beau graphique.
5) Qu’en est‑il de BFQ ?
BFQ est souvent excellent pour l’équité interactive, notamment sur postes de travail. Sur des serveurs avec ZFS, il est moins souvent le bon choix car il peut
ajouter de l’overhead et ses objectifs d’équité peuvent ne pas correspondre à votre workload. Testez‑le si vous avez besoin d’équité par cgroup et pouvez tolérer le coût.
6) Le choix d’ordonnanceur affecte‑t‑il les scrubs et resilvers ZFS ?
Indirectement, oui. Scrubs/resilvers génèrent des lectures soutenues et des opérations sur métadonnées. Sur les HDD, mq-deadline peut empêcher que ces opérations
soient ensevelies derrière des écritures (ou inversement), améliorant la prévisibilité. Sur NVMe, none garde généralement le pipeline efficace.
7) Mon SSD est SATA mais ressemble à un NVMe en performance. Dois‑je quand même utiliser mq-deadline ?
Commencez par mq-deadline. SATA est encore limité par un modèle de commandes différent et souvent un queueing matériel plus simple. Certains SATA SSD entreprise se comportent bien en none,
mais mq-deadline est une baseline de latence plus sûre sous workloads mixtes.
8) Puis‑je définir un ordonnanceur pour tout le pool ?
Vous définissez les ordonnanceurs par périphérique bloc, pas par pool. Un pool peut inclure des vdevs HDD plus un SLOG NVMe ; ils doivent utiliser des ordonnanceurs différents.
Traitez les dispositifs de log/special comme des périphériques de première importance — ils peuvent dominer la latence perçue.
9) Pourquoi mes changements reviennent‑ils même avec des règles udev ?
Parce que quelque chose d’autre le définit aussi (initramfs rules, outils de tuning de la distro, ou une règle udev en conflit). Vérifiez l’ordre des règles
et déboguez avec udevadm test si nécessaire. La solution est de standardiser un mécanisme et d’éliminer le concurrent.
10) Quelle est la baseline la plus simple et sûre pour des flottes mixtes ?
HDD : mq-deadline. SATA/SAS SSD : mq-deadline. NVMe : none. Puis validez avec des canaris par génération matérielle.
Cela vous apporte 90 % des bénéfices avec un risque minimal.
Conclusion : les prochaines étapes à effectuer réellement
Si vous exécutez ZFS sur Linux, la décision sur l’ordonnanceur IO est agréablement peu romantique :
mq-deadline pour les HDD et la plupart des SATA/SAS SSD, none pour NVMe. Tout le reste est un cas particulier qui nécessite des preuves.
Prochaines étapes qui rapportent :
- Inventoriez les périphériques et confirmez les ordonnanceurs actuels via sysfs.
- Mappez les périphériques aux rôles ZFS vdev (data vs log vs special).
- Appliquez la politique d’ordonnanceur baseline et rendez‑la persistante via des règles udev.
- Mesurez la latence tail avant/après avec iostat, zpool iostat, et les p95/p99 de votre application.
- Si la latence reste mauvaise, arrêtez de blâmer l’ordonnanceur et investigatez la conception des écritures sync, le matériel défaillant, et le layout des vdevs.
L’ordonnanceur IO n’est pas magique. C’est un agent de circulation. Placez‑le là où il aide, retirez‑le où il nuit, et gardez votre budget d’incidents pour des problèmes qui le méritent vraiment.