Vous remplacez ext4 par ZFS parce que vous voulez des sommes de contrôle, des snapshots, send/receive, et la tranquillité d’esprit que votre stockage n’est plus tenu par l’espoir.
Puis les graphiques arrivent. La latence bondit, le débit plafonne, et le SSD qui ressemblait à une fusée sur ext4 se comporte soudain comme s’il attendait une approbation managériale.
Ce n’est généralement pas un « ZFS lent ». C’est ZFS qui dit la vérité sur le périphérique, la charge de travail et le modèle de file d’attente que vous avez accidentellement créé.
La profondeur de file d’attente est l’endroit où beaucoup de ces incompréhensions vont vivre.
Ce que signifie réellement la profondeur de file d’attente (et pourquoi cela vous concerne)
La profondeur de file d’attente correspond au nombre d’opérations I/O « en vol » vers un périphérique en même temps. Si vous n’avez qu’une seule requête en cours à la fois,
vous conduisez essentiellement une voiture de sport en première vitesse tout en respectant scrupuleusement une limite de 10 mph.
Les SSD, notamment NVMe, sont conçus pour fonctionner avec du parallélisme. Ils cachent le travail interne (mappage du flash translation layer, garbage collection,
wear leveling) derrière plusieurs commandes en attente. Avec une faible profondeur de file d’attente, vous obtenez une latence correcte mais un débit médiocre. Avec une profondeur plus élevée,
vous obtenez généralement un débit supérieur… jusqu’à la falaise où la latence explose.
Ce que beaucoup oublient : la profondeur de file d’attente n’est pas seulement une propriété de votre outil de benchmark. C’est une propriété émergente de toute la pile :
la concurrence applicative, l’ordonnanceur I/O du noyau, le comportement du système de fichiers, le cache, la politique de writeback et le firmware du périphérique.
ext4 et ZFS diffèrent radicalement dans la manière dont ils produisent des I/O, quand ils les soumettent et comment ils transforment des écritures aléatoires en quelque chose que le périphérique peut digérer.
De plus, « profondeur de file d’attente » a deux sens courants :
- Profondeur côté hôte : combien de requêtes l’OS a soumises mais que le périphérique n’a pas terminées.
- Profondeur côté périphérique : combien de commandes sont en attente dans les files du périphérique (NVMe a plusieurs files de soumission/complétion).
Si vous avez déjà vu un SSD faire excellent à QD=1 et affreux à QD=32, félicitations : vous avez rencontré la différence entre « rapide » et « stable ».
Pourquoi ext4 peut paraître plus rapide sur le même SSD
Le mode de fonctionnement normal d’ext4 est : accepter les écritures, laisser le cache page du noyau les absorber, et les pousser plus tard via le writeback.
Pour de nombreuses charges, cela signifie que l’application a l’impression que c’est rapide parce qu’elle écrit principalement en RAM. Quand le flush arrive,
la couche bloc et l’ordonnanceur du noyau peuvent combiner, réordonner et enchaîner les I/O de façons que votre SSD apprécie.
ZFS fait aussi du caching, mais selon des règles différentes. ZFS est copy-on-write et basé sur des transactions. Il accumule les changements en mémoire,
puis les valide en groupes de transactions (TXG). Il vérifie aussi les données avec des checksums, écrit de nouveaux blocs au lieu d’écraser les anciens,
et maintient des métadonnées qu’ext4 n’a pas à suivre de la même manière.
Cela peut être une victoire ou un piège de performance, selon votre charge et votre périphérique :
- Victoire : ZFS peut agréger de petites écritures aléatoires en écritures plus larges et séquentielles au moment du commit TXG, ce que les SSD gèrent souvent bien.
- Piège : ZFS peut créer des rafales : beaucoup d’I/O atteignent le périphérique en même temps, la profondeur de file d’attente monte en flèche et certains SSD s’effondrent.
- Piège : L’I/O des métadonnées ZFS peut être plus intense (surtout avec snapshots, petits blocs et datasets à fort churn).
- Piège : Les écritures sync (fsync, O_DSYNC, bases de données) peuvent être brutalement honnêtes. ext4 s’en sort souvent avec le « ordered mode + barriers »
tandis que ZFS insiste sur la sémantique correcte. La correction peut sembler lente quand votre matériel n’est pas prévu pour cela.
Retenue pratique : ext4 « paraît souvent plus rapide » dans des benchmarks qui mesurent le temps d’accusé de réception plutôt que le temps jusqu’à durabilité,
ou qui testent accidentellement le cache page. ZFS a tendance à exposer le coût réel de la durabilité, en particulier pour les applications sync-intensives.
Comment ZFS construit l’I/O : agrégation, TXG et l’écart avec la réalité
The TXG rhythm: smooth on paper, spiky in production
ZFS collecte les données dirty en mémoire et les commit périodiquement comme un TXG. Ce commit est l’endroit où ZFS écrit beaucoup de choses :
nouveaux blocs de données, nouveaux blocs de métadonnées, blocs indirects mis à jour, spacemaps, et enfin les uberblocks.
Si le système est occupé, vous pouvez obtenir un pipeline quasi-continu de TXG, mais chacun a quand même un moment de « poussée ».
Les rafales ne sont pas intrinsèquement mauvaises. Les SSD aiment le parallélisme. Le problème survient lorsque la rafale pousse le périphérique dans son pire mode comportemental :
garbage collection interne, exhaustion du cache SLC, surcharge de gestion des queues par le firmware, ou throttling thermique.
ZFS n’a pas créé ces faiblesses ; il les a juste découvertes plus vite qu’ext4.
ZIO pipeline and concurrency knobs
ZFS ne soumet pas l’I/O comme un flux unique. Il a un pipeline (ZIO) avec des étapes : checksum, compression, gang blocks, allocation,
émission d’I/O, complétion, etc. ZFS dispose aussi de limites de concurrence internes par vdev et par classe d’I/O.
Ces limites ont évolué selon les versions d’OpenZFS et les systèmes d’exploitation, mais l’idée reste : ZFS essaie d’être équitable et stable,
pas « profondeur de file d’attente maximale à tout prix ».
Si vous venez d’ext4 et pensez « plus de profondeur de file d’attente est toujours mieux », ZFS ne sera pas d’accord en production.
ZFS préfère généralement une concurrence contrôlée parce que la concurrence non contrôlée se transforme en pics de latence,
et les pics de latence entraînent des bases de données mécontentes et des timeouts.
Why zvols can behave differently than datasets
Un dataset ZFS est un système de fichiers avec recordsize (souvent 128K par défaut). Un zvol est un périphérique bloc avec volblocksize (souvent 8K par défaut).
Les schémas d’I/O diffèrent, les métadonnées diffèrent, et l’amplification d’écriture diffère. Avec les zvols, vous pouvez facilement vous retrouver avec
beaucoup de petites écritures synchrones—surtout avec des images VM et des bases de données qui adorent fsync.
ext4 sur un bloc brut peut bénéficier d’un writeback et d’un reorder décent. Un zvol peut être plus « littéral », et vous en payez le prix.
Ce n’est pas une faute morale. C’est un choix d’ingénierie que vous devez aligner avec la charge de travail.
Une idée paraphrasée, attribuée parce que c’est la chose la plus proche d’une écriture sacrée pour les opérations :
paraphrased idea: “Hope is not a strategy.”
— souvent évoquée dans les cercles SRE à l’esprit, mais ici gardée volontairement non verbatim.
(Et oui, vous devriez mesurer, pas espérer.)
Où les SSD étouffent : falaises de latence, limites du firmware et I/O mixte
The latency cliff is real
Beaucoup de SSD grand public et prosumer sont optimisés pour des rafales de type desktop, une faible profondeur de file d’attente et des mixes orientés lecture.
Ils brillent dans des tests synthétiques ext4 qui ne maintiennent pas la pression assez longtemps pour déclencher les parties laides.
Sous des commits TXG ZFS ou des écritures synchrones soutenues, le périphérique atteint un état stable, le cache SLC se vide,
et soudain votre SSD « 3 GB/s » fait du « veuillez patienter » à 40–200 MB/s avec une latence qui rend votre appli fantomatique.
Firmware fairness vs. throughput tricks
Les SSD d’entreprise sacrifient souvent les chiffres de pic pour une latence tail prévisible à des profondeurs de file d’attente plus élevées.
Ils sont ennuyeux. L’ennui, c’est bien. Les SSD grand public visent souvent des chiffres marketing en s’appuyant sur des caches et un regroupement agressif des écritures.
Cela peut être excellent jusqu’à ce que la charge devienne continue et multithread. Les charges ZFS sont fréquemment exactement cela : continues et multithread.
Mixed reads and writes with metadata
Les métadonnées ZFS ne sont pas gratuites. Les snapshots et clones peuvent multiplier le travail de métadonnées. Les petites écritures aléatoires créent plus de churn.
Si votre pool est presque plein, l’allocation d’espace devient plus difficile et les spacemaps s’activent davantage. Le SSD voit un mix :
petites lectures pour les métadonnées, écritures pour les données, et points sync pour la cohérence.
Certains disques gèrent cela avec élégance. D’autres réagissent comme un enfant à qui l’on donne un violon.
Blague #1 : J’ai demandé une fois à un SSD grand public ses performances d’écriture en état stable. Il a répondu en thermal throttling par dépit.
Alignment and ashift: the silent performance tax
Si l’ashift de votre pool ne correspond pas à la vraie taille de secteur physique du périphérique, vous pouvez forcer un comportement read-modify-write.
Cela signifie que chaque écriture « petite » peut se transformer en plusieurs opérations internes. ext4 peut aussi souffrir d’un mauvais alignement,
mais ZFS rend plus facile la création d’une mauvaise configuration permanente au moment de la création du pool.
Sync write semantics: ZFS refuses to lie
Le moyen le plus rapide de rendre ZFS « lent » est d’exécuter une charge sync-intensive sur des périphériques sans protection contre la perte d’alimentation et sans SLOG approprié,
tout en s’attendant à un comportement similaire à ext4. ZFS honorera la requête : « rendre ceci durable ».
Votre SSD fera sa meilleure impression d’un disque rotatif.
Faits intéressants et contexte historique
- ZFS a été créé chez Sun Microsystems au milieu des années 2000, conçu pour l’intégrité de bout en bout et le stockage en pool, pas pour chasser des trophées de benchmark mono-thread.
- Le copy-on-write n’a pas été inventé par ZFS, mais ZFS l’a popularisé pour les systèmes de fichiers généralistes à grande échelle avec gestion de volumes intégrée.
- NVMe a introduit plusieurs files matérielles pour réduire la contention des locks et la charge CPU comparé à SATA/AHCI, rendant la profondeur de file d’attente et l’affinité CPU plus visibles en performance.
- Les premiers contrôleurs SSD étaient célèbres pour leurs falaises d’écriture quand leurs tables de mappage internes ou caches se remplissaient ; les disques modernes sont meilleurs, mais la forme de la falaise existe toujours.
- ZFS utilise depuis longtemps les groupes de transactions pour regrouper les modifications ; ce regroupement peut améliorer le débit mais crée aussi de la rafale qui expose les périphériques faibles.
- Les ordonnanceurs I/O Linux ont évolué de CFQ à deadline à mq-deadline puis none ; avec NVMe, beaucoup de stacks préfèrent « none », déplaçant plus de comportement vers le périphérique et le système de fichiers.
- Les tailles de secteurs sont compliquées : 512e et 4Kn existent parce que l’industrie a essayé de passer à 4K sans tout casser d’un coup.
- Le checksumming des blocs de données implique que les lectures ZFS sont souvent vérifiées de bout en bout ; c’est un petit coût CPU mais réel, et cela change la sensation de « rapidité » sous charge.
Mode d’emploi pour un diagnostic rapide
Quand ZFS « étouffe », vous ne commencez pas en changeant des tunables au hasard. Vous commencez par trouver quelle file se remplit :
application, ARC, ZIO, vdev, couche bloc du noyau, ou le SSD lui‑même. Voici une séquence rapide qui fonctionne quand le pager hurle.
First: identify whether you’re bound by latency, bandwidth, CPU, or sync
- Vérifiez la latence et le queueing par périphérique (iostat). Si
awaitetaqu-szmontent, le périphérique est saturé ou dysfonctionne. - Vérifiez l’attente au niveau ZFS (zpool iostat -w). Si ZFS montre de longs temps d’attente, vous êtes bottlenecké sous ZFS, pas dans l’ARC.
- Vérifiez le CPU et les softirqs. Si le CPU est saturé dans le noyau ou softirq, le « problème stockage » peut être une contention CPU.
- Vérifiez si la charge est sync-heavy. Si oui, traitez d’abord comme un problème de durabilité.
Second: isolate which kind of I/O is hurting
- Reads vs writes : les lectures sont-elles lentes à cause d’un thrashing des métadonnées ?
- Small random vs large sequential : recordsize/volblocksize est-il mal ajusté ?
- Steady state vs burst : les performances s’effondrent-elles après une minute ? C’est le comportement SLC cache/GC/throttling thermique.
Third: confirm pool layout and the non-negotiables
- Remplissage du pool : si vous êtes au-dessus d’environ 80–90% sur beaucoup de pools, les coûts d’allocation augmentent et les SSD souffrent.
ashift: un ashift erroné est pour toujours sauf si vous reconstruisez.- Stratégie sync : si vous avez besoin de sémantique sync, utilisez du matériel approprié ou acceptez le coût.
Tâches pratiques : commandes, sorties, décisions (12+)
Voici les vérifications que j’exécute quand quelqu’un me dit « ext4 était plus rapide ». L’objectif n’est pas de collecter des trivia.
L’objectif est de décider quoi réparer, quoi laisser, et quoi reconcevoir.
Task 1: Confirm the device and transport (NVMe vs SATA, link speed)
cr0x@server:~$ lsblk -d -o NAME,MODEL,TRAN,ROTA,SIZE
NAME MODEL TRAN ROTA SIZE
nvme0n1 SAMSUNG_MZVLW1 nvme 0 953.9G
sda ST2000DM008 sata 1 1.8T
Ce que cela signifie : TRAN vous indique si vous êtes en NVMe ou SATA ; ROTA montre si c’est rotatif.
Si vous attendiez NVMe et que vous voyez SATA, votre « problème ZFS » peut être un problème d’approvisionnement.
Décision : Vérifiez la cible de test. Ne tunez pas ZFS pour la mauvaise classe de périphérique.
Task 2: Check kernel I/O scheduler for the device
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
Ce que cela signifie : NVMe fonctionne souvent avec none, signifiant un ordonnancement hôte minimal.
Décision : Si vous voyez bfq sur un NVMe rapide et que vous recherchez le débit, envisagez none ou mq-deadline.
Si vous visez la stabilité de la latence sous charge mixte, mq-deadline peut être plus raisonnable que « faire confiance au firmware ».
Task 3: Observe queue depth and latency live (block layer view)
cr0x@server:~$ iostat -x 1 nvme0n1
avg-cpu: %user %nice %system %iowait %steal %idle
8.21 0.00 4.88 2.44 0.00 84.47
Device r/s w/s rKB/s wKB/s rrqm/s wrqm/s %util await aqu-sz
nvme0n1 1200 9000 98000 620000 0.0 0.0 99.5 6.80 62.4
Ce que cela signifie : aqu-sz est la taille moyenne de la file ; await est la latence moyenne.
%util proche de 100% signifie que le périphérique est occupé.
Décision : Si la taille de la file est énorme et que la latence augmente, vous satuez le périphérique ou frappez une falaise firmware.
Si la file est petite mais le débit faible, votre goulot d’étranglement est au-dessus du périphérique (CPU, sync, ou throttling ZFS).
Task 4: Check ZFS vdev latency and queueing
cr0x@server:~$ zpool iostat -v 1
capacity operations bandwidth
pool alloc free read write read write
tank 1.23T 2.41T 900 7200 110M 690M
mirror 1.23T 2.41T 900 7200 110M 690M
nvme0n1 - - 450 3600 55M 345M
nvme1n1 - - 450 3600 55M 345M
Ce que cela signifie : Cela vous dit si ZFS émet des I/O et comment elles sont distribuées entre les vdevs.
Décision : Si un vdev feuille est plus lent, il tirera tout le pool vers le bas. Remplacez l’enfant problématique ou rééquilibrez la configuration.
Task 5: Confirm pool health and error counters
cr0x@server:~$ zpool status -v
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
errors: No known data errors
Ce que cela signifie : Si vous avez des retries, des erreurs de checksum ou des périphériques dégradés, des problèmes de performance sont attendus.
Décision : Réparez la fiabilité d’abord. Tuner autour d’erreurs est la façon dont les incidents deviennent des outages.
Task 6: Check dataset properties that change I/O shape
cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,compression,atime,primarycache,sync tank/data
NAME PROPERTY VALUE
tank/data recordsize 128K
tank/data compression zstd
tank/data atime off
tank/data primarycache all
tank/data sync standard
Ce que cela signifie : recordsize affecte l’amplification d’écriture pour les petites écritures aléatoires ; sync affecte le comportement de durabilité.
Décision : Pour des bases de données avec pages 8K, envisagez recordsize=16K ou 8K seulement si vous comprenez le coût sur les métadonnées.
Ne faites pas de cargo-culting ; mesurez.
Task 7: Check zvol settings if you’re serving VM disks or iSCSI
cr0x@server:~$ zfs get -o name,property,value -s local,default volblocksize,compression,sync,logbias tank/vm0
NAME PROPERTY VALUE
tank/vm0 volblocksize 8K
tank/vm0 compression off
tank/vm0 sync standard
tank/vm0 logbias latency
Ce que cela signifie : Un petit volblocksize peut augmenter les IOPS mais peut aussi pénaliser le pool avec des métadonnées et de la fragmentation.
Décision : Si vous voyez des écritures sync lourdes et aucun SLOG, attendez-vous à de la douleur. Si vous avez un SLOG, logbias=latency est raisonnable.
Task 8: Detect sync-heavy behavior from the application side
cr0x@server:~$ strace -f -tt -e trace=fdatasync,fsync,pwrite64 -p 2143
12:19:41.102334 fdatasync(7) = 0
12:19:41.104981 pwrite64(7, "...", 8192, 123904) = 8192
12:19:41.106204 fdatasync(7) = 0
Ce que cela signifie : Si vous voyez des fsync/fdatasync fréquents, votre charge tient à la durabilité et à l’ordre.
Décision : Traitez cela comme un problème de latence sync. Envisagez un SLOG (avec PLP), ajustez sync seulement en connaissance de cause.
Task 9: Verify SLOG presence and whether it’s actually being used
cr0x@server:~$ zpool status
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
logs
nvme2n1 ONLINE 0 0 0
Ce que cela signifie : Un périphérique sous logs est un intent log séparé (SLOG).
Décision : Si vous exécutez des charges sync-heavy, un SLOG avec PLP peut réduire la latence tail. Si votre SLOG est un SSD grand public sans PLP,
vous achetez de la vitesse au prix du risque d’intégrité. Ne le faites pas.
Task 10: Check pool fragmentation and capacity pressure
cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
NAME SIZE ALLOC FREE CAP FRAG HEALTH
tank 3.64T 3.20T 440G 87% 62% ONLINE
Ce que cela signifie : Un cap élevé et une frag élevée corrèlent souvent avec un pire comportement d’allocation et plus de churn de métadonnées.
Décision : Si vous êtes presque plein, arrêtez de tuner et commencez à planifier la capacité. L’espace libre, c’est de la performance.
Task 11: Measure ZFS ARC behavior (are you actually caching?)
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:20:10 9850 1200 12 500 5 700 7 0 0 32.0G 32.0G
12:20:11 10310 1500 15 800 8 700 7 0 0 32.0G 32.0G
12:20:12 9980 2200 22 1600 16 600 6 0 0 32.0G 32.0G
Ce que cela signifie : Une miss% croissante signifie que vous allez sur disque plus souvent.
Décision : Si votre working set ne tient pas et que vous avez une charge orientée lecture, envisagez plus de RAM ou une restructuration des datasets.
N’ajoutez pas L2ARC en réflexe ; cela peut ajouter de la surcharge.
Task 12: Check TRIM/discard status (SSD steady-state behavior)
cr0x@server:~$ zpool get autotrim tank
NAME PROPERTY VALUE SOURCE
tank autotrim on local
Ce que cela signifie : autotrim=on aide les SSD à maintenir leurs performances en leur indiquant les blocs libérés.
Décision : Si autotrim est off sur des pools SSD et que vous avez du churn, envisagez de l’activer (après validation du support OS/ZFS).
Task 13: Confirm ashift (alignment) on each vdev
cr0x@server:~$ zdb -C tank | grep -E 'ashift|path' -n
128: path: '/dev/nvme0n1'
135: ashift: 12
142: path: '/dev/nvme1n1'
149: ashift: 12
Ce que cela signifie : ashift: 12 correspond à des secteurs 4K. Beaucoup de SSD veulent au moins cela.
Décision : Si vous voyez ashift: 9 sur des SSD modernes, vous avez probablement une taxe de performance permanente. Reconstruisez le pool correctement.
Task 14: Check NVMe health indicators and throttling hints
cr0x@server:~$ nvme smart-log /dev/nvme0n1
Smart Log for NVME device:nvme0n1 namespace-id:ffffffff
critical_warning : 0x00
temperature : 71 C
available_spare : 100%
percentage_used : 3%
data_units_read : 123,456,789
data_units_written : 98,765,432
host_read_commands : 4,321,000,000
host_write_commands : 7,654,000,000
controller_busy_time : 12,345
media_errors : 0
num_err_log_entries : 0
Ce que cela signifie : 71°C frôle la zone de throttling pour certains disques.
Décision : Si les performances s’effondrent sous charge et que la température est élevée, corrigez le refroidissement avant d’écrire un document de tuning.
Task 15: Reproduce with a benchmark that controls queue depth and bypasses cache
cr0x@server:~$ fio --name=randwrite --filename=/tank/data/fio.test --size=8G --direct=1 --ioengine=libaio --rw=randwrite --bs=4k --iodepth=32 --numjobs=4 --group_reporting
randwrite: (groupid=0, jobs=4): err= 0: pid=8812: Fri Dec 22 12:24:33 2025
write: IOPS=52.4k, BW=205MiB/s (215MB/s)(8192MiB/39945msec)
slat (usec): min=4, max=980, avg=18.21, stdev=9.44
clat (usec): min=50, max=120000, avg=2400.15, stdev=7800.22
lat (usec): min=60, max=120500, avg=2419.10, stdev=7800.40
Ce que cela signifie : La latence moyenne est de 2,4ms mais le max est 120ms : la latence tail est vilaine.
Décision : Si ext4 paraît « plus rapide », répétez le même profil fio sur ext4 avec direct=1.
Si la latence tail sous ZFS est pire, concentrez-vous sur le sync, le remplissage du pool, le comportement thermique/firmware du périphérique et le mismatch du pattern I/O.
Erreurs courantes : symptôme → cause racine → correctif
1) « Le débit est correct, mais la latence pique toutes les quelques secondes »
Symptôme : Pics de latence périodiques ; timeouts applicatifs ; les graphiques ressemblent à un battement de cœur.
Cause racine : Rafales de commit TXG frappant un SSD faible en état stable (exhaustion du cache SLC, GC) ou throttling thermique.
Correctif : Confirmez avec des tests fio en état stable et la température NVMe. Améliorez le refroidissement, choisissez des SSD avec des écritures soutenues prévisibles, gardez le pool hors pression de capacité.
2) « ext4 bat ZFS de 2–5× sur les écritures dans mon test »
Symptôme : Copie de fichier simple ou benchmark naïf rapporte ext4 beaucoup plus rapide.
Cause racine : Le benchmark mesure le cache page et le delayed allocation, pas la durabilité ; le test ZFS touche la sémantique sync ou l’I/O direct.
Correctif : Utilisez direct=1 dans fio, ou au moins videz les caches ; comparez pommes avec pommes (sync vs async, buffered vs direct).
3) « Le stockage VM sur zvol est lent, les datasets semblent corrects »
Symptôme : IOPS d’écriture aléatoire faibles, charges fsync-heavy qui bloquent, plaintes des invités.
Cause racine : Petit volblocksize + charge cliente sync-heavy + pas de SLOG ; aussi possible mismatch volblocksize vs filesystem invité.
Correctif : Ajoutez un SLOG approprié (PLP), envisagez d’adapter volblocksize à la charge, pensez au stockage basé dataset pour certains patterns VM, validez les attentes sync.
4) « C’était mieux après avoir activé la compression »
Symptôme : CPU plus élevé, débit inférieur, plus de latence sous charge.
Cause racine : Le CPU devient un goulet, ou l’algorithme de compression est trop lourd pour le budget de cœurs ; cela peut aussi changer la distribution de taille d’I/O.
Correctif : Utilisez un algorithme plus rapide (par ex. zstd à un niveau bas), gérez la contention CPU, mesurez de nouveau. La compression n’est pas gratuite ; c’est un compromis.
5) « Tout allait bien jusqu’à ce que le pool atteigne 85–90% »
Symptôme : Les écritures ralentissent, les lectures de métadonnées augmentent, la fragmentation monte.
Cause racine : L’allocation devient coûteuse ; les SSD voient plus d’écritures aléatoires ; ZFS dispose de moins de régions contiguës.
Correctif : Ajoutez de la capacité, supprimez/déplacez des données, réduisez le churn de snapshots, gardez de la marge. Le tuning ne remplace pas l’espace libre.
6) « Nous avons mis sync=disabled et c’est rapide maintenant »
Symptôme : Les performances s’améliorent drastiquement ; tout le monde célèbre.
Cause racine : Vous avez troqué la durabilité contre la vitesse. Un crash peut perdre des écritures reconnues. Sur certains systèmes cela peut corrompre les invariants applicatifs.
Correctif : Annulez à moins d’avoir une raison documentée et un acceptation de perte de données. Utilisez SLOG ou de meilleurs périphériques à la place.
Trois mini-histoires du monde de l’entreprise
Mini-histoire 1 : L’incident causé par une mauvaise hypothèse
Une entreprise SaaS de taille moyenne a déplacé un cluster PostgreSQL chargé d’ext4 en RAID10 vers des miroirs ZFS sur des NVMe « rapides ».
Le plan de migration était solide : snapshots, points de rollback, basculement contrôlé, le classique.
L’hypothèse non dite : « NVMe, c’est NVMe, ça ira. »
En quelques heures, ils ont observé des blocages de requêtes périodiques. Pas une lenteur constante—pire. Des pauses aléatoires de 2–10 secondes qui ont vidé les pools de connexions.
Les logs de la base montraient des rafales de fsync lents. L’OS semblait calme. Le CPU allait bien. Le réseau allait bien. Les graphiques de stockage ressemblaient à un sismographe.
La cause racine n’était pas le surcoût de correction de ZFS. C’était le comportement d’écriture en état stable du modèle de SSD sous une pression sync soutenue.
Sous ext4, la charge avait été « lissée » par le cache page et le writeback ; le contrôleur RAID (avec batterie) aidait aussi.
Sous ZFS, avec des sémantiques sync correctes et sans périphérique de log dédié, le pool a forcé les SSD à montrer leur vraie latence tail.
Le correctif fut peu glamour : ajouter des devices de log avec protection perte d’alim, ajuster la topologie du pool pour la charge,
et remplacer le modèle de SSD le plus mauvais par des disques à latence soutenue prévisible.
Le postmortem fut encore moins glamour : les checklists d’achats incluent désormais des tests d’écriture soutenue, pas seulement des IOPS sur la fiche technique.
Mini-histoire 2 : L’optimisation qui a mal tourné
Une équipe plateforme interne gérait un cluster virtualisé multi-tenant. Ils étaient fiers de leurs compétences ZFS et voulaient un maximum de performances.
Ils ont vu un post de forum disant, en substance, « augmentez la concurrence ; ZFS est conservateur ».
Ils ont ajusté plusieurs paramètres du module ZFS pour permettre des queues plus profondes et plus d’I/O en attente par vdev.
En bench mono-tenant, c’était super. Le débit augmentait. Tout le monde partageait des captures d’écran. Puis la charge réelle est revenue :
des dizaines de VMs effectuant lectures, écritures et rafales sync mélangées. La latence tail s’est détériorée. Pas un peu ; « des utilisateurs ouvrent des tickets » détériorée.
Le système était devenu excellent pour saturer les SSD et terrible pour garder une latence prévisible.
Sous charge mixte, les queues plus profondes causaient un empaquetage des requêtes. Le firmware SSD a réagi par du reorder interne et de longues pauses de garbage collection.
Les métriques moyennes semblaient correctes. Le 99.9e percentile avait pris feu.
Ils ont annulé les modifications et se sont concentrés sur l’isolation des charges : pools séparés pour voisins bruyants,
SLOGs appropriés pour tenants sync-heavy, et garder le throttling par défaut de ZFS sauf raison mesurée.
Les performances « diminuaient » sur les tests synthétiques, et la plateforme était plus rapide de la seule manière qui importe aux clients : moins d’interruptions.
Mini-histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une société liée à la finance (ce qui signifie audits et mémoires longues) utilisait ZFS pour un pipeline d’ingestion de logs.
Pas glamour. Principalement des écritures séquentielles avec des compactions périodiques. Ils avaient une politique : ne jamais remplir les pools au-delà de 75%,
toujours garder autotrim activé sur les pools SSD, et toujours tester les nouveaux modèles SSD avec 30 minutes d’écriture en steady-state avant approbation.
Un trimestre, un fournisseur a substitué un modèle SSD « plus récent » pour des contraintes d’approvisionnement. Sur le papier il était plus rapide.
L’équipe a malgré tout exécuté son test steady-state. À la minute 12, la latence d’écriture a bondi d’un ordre de grandeur et y est restée.
Le disque ne défaillait pas ; il faisait juste ce qu’il fait quand son cache et ses tables de mappage sont sous pression soutenue.
Ils ont refusé la substitution et conservé le modèle plus ancien. Un mois plus tard, un autre département a déployé le modèle substitué sur un autre système
et a passé des semaines à chasser des timeouts intermittents. L’équipe ZFS n’a pas eu besoin de dire « je vous l’avais bien dit » à voix haute.
Le processus ennuyeux—marge de capacité, politique de trim et tests steady-state—a évité un incident lent mais durable.
Blague #2 : Le meilleur tuning de performance est parfois une feuille de calcul et la capacité de dire « non », ce qui explique pourquoi c’est si rarement appliqué.
Listes de contrôle / plan étape par étape
Étape par étape : reproduire la comparaison ext4 vs ZFS sans se mentir
- Choisissez le même périphérique et le même style de partitionnement. Ne comparez pas ext4 sur un disque brut à ZFS sur un zvol sparse sauf si c’est intentionnel.
- Exécutez des tests direct I/O en premier. Utilisez fio avec
direct=1pour mesurer le périphérique + système de fichiers, pas la RAM. - Testez à plusieurs profondeurs de file d’attente. QD=1, 4, 16, 32. Surveillez où la latence se casse. Ce point de rupture compte plus que les IOPS peak.
- Exécutez suffisamment longtemps pour atteindre l’état stable. Des minutes, pas des secondes. Beaucoup de falaises SSD apparaissent après que les caches sont épuisés.
- Séparez les tests sync et async. Si votre charge fait fsync, testez fsync. Si ce n’est pas le cas, ne vous punissez pas avec des tests sync.
Étape par étape : ordre de tuning sûr pour la production (moindre regret d’abord)
- Corrigez les réalités matérielles/firmware. Refroidissement, bonne classe de SSD, évitez les disques bon marché pour des charges sync-heavy.
- Corrigez la capacité et la topologie du pool. Marge, design des vdevs, miroirs vs RAIDZ selon les besoins de latence.
- Corrigez les mismatches évidents de dataset. recordsize/volblocksize, atime, niveau de compression.
- Adressez correctement les sémantiques sync. SLOG avec PLP, ou acceptez le coût de performance.
- Ensuite seulement touchez aux tunables internes profonds de ZFS. Et faites-le avec plans de rollback et résultats mesurés.
Checklist : avant de blâmer ZFS
- Comparez-vous des écritures bufferisées sur ext4 vs des écritures durables sur ZFS ?
- Le pool est-il au-dessus de 80–85% de capacité ou fortement fragmenté ?
- La température du SSD est-elle élevée sous charge ?
- La charge exécute-t-elle fréquemment fsync/fdatasync ?
- L’
ashiftest-il correct ? - Utilisez-vous des zvols là où des datasets seraient plus simples (ou vice versa) ?
- Avez-vous des SSD d’entreprise prévisibles ou des modèles grand public en rafales ?
FAQ
1) Est-ce que ZFS est « basse profondeur de file d’attente » par conception ?
ZFS tend à gérer la concurrence pour protéger la latence et l’équité. Il peut pousser une profondeur de file d’attente élevée sous charge, mais il essaie de ne pas faire fondre le périphérique.
Si votre SSD nécessite un QD extrême pour performer, c’est une caractéristique du périphérique que vous devriez valider en état stable.
2) Pourquoi certains SSD passent de bons benchmarks sur ext4 à terribles sur ZFS ?
Les benchmarks ext4 touchent souvent le cache page et le delayed writeback, masquant les falaises du périphérique. ZFS peut pousser des schémas plus véridiques : rafales lors des commits TXG,
plus de churn de métadonnées, et un comportement sync explicite. Les SSD faibles en steady-state sont exposés.
3) Dois-je changer l’ordonnanceur I/O Linux pour NVMe quand j’utilise ZFS ?
Parfois. « none » est courant et souvent adéquat. Si vous avez besoin de stabilité de latence sous charges mixtes, mq-deadline peut aider.
N’attendez pas de miracles ; les tweaks d’ordonnanceur ne sauveront pas un disque qui s’effondre sous écritures soutenues.
4) L’ajout d’un SLOG améliore-t-il toujours les performances ?
Seulement pour les écritures sync. Pour des charges majoritairement async, le SLOG apporte peu. Pour des charges sync-heavy, un SLOG PLP approprié peut fortement réduire la latence tail.
Un SLOG sans PLP est un pari sur la fiabilité, pas une optimisation.
5) Les zvols sont-ils intrinsèquement plus lents que les datasets ?
Pas intrinsèquement, mais ils se comportent différemment. Les zvols peuvent amplifier les petites écritures aléatoires et les patterns sync. Les datasets peuvent agréger les écritures plus naturellement.
Choisissez selon la charge : images VM et iSCSI veulent souvent des zvols ; les charges fichiers préfèrent souvent des datasets.
6) Quelle est la plus grosse « boulette » qui cause les douleurs SSD sous ZFS ?
Exécuter une charge sync-heavy sur des SSD grand public sans PLP et sans vrai SLOG, puis attendre une faible latence tail.
En deuxième position : remplir les pools trop et se demander pourquoi l’allocation est lente.
7) Dois-je tuner recordsize à 8K pour les bases de données ?
Parfois, mais ce n’est pas gratuit. Un recordsize plus petit peut réduire l’amplification en lecture pour les petites lectures mais augmente les métadonnées et le risque de fragmentation.
Beaucoup de déploiements DB se débrouillent bien avec 16K ou 32K ; certains ont besoin de 8K. Mesurez avec une concurrence réaliste et des tests steady-state.
8) Comment savoir si je vois une falaise SLC cache du SSD ?
Exécutez un test d’écriture soutenue assez long (10–30 minutes) avec direct I/O et une profondeur de file d’attente réaliste.
Si le débit chute fortement après une courte période et que la latence explose, c’est une exhaustion de cache ou un comportement GC classique.
9) Est-ce sûr d’activer autotrim ?
Sur OpenZFS et SSD modernes, autotrim est couramment utilisé et aide les performances en état stable. Validez toutefois dans votre environnement.
Si vous avez un firmware ancien ou des couches de virtualisation bizarres, testez d’abord.
10) Pourquoi les performances changent-elles avec les snapshots ?
Les snapshots augmentent le travail de métadonnées et peuvent accroître la fragmentation sous churn. Les suppressions deviennent plus coûteuses car les blocs sont référencés par des snapshots.
Cela peut modifier le comportement d’écriture et augmenter l’I/O aléatoire, que certains SSD gèrent mal à des profondeurs de file d’attente élevées.
Conclusion : prochaines étapes que vous pouvez réellement faire aujourd’hui
Si un SSD « vole sur ext4 et étouffe sur ZFS », vous observez probablement une des trois choses : un benchmark qui flatte ext4 en testant le cache,
un contrôle de réalité sur la latence sync, ou un SSD qui s’effondre sous I/O mixte soutenue quand la profondeur de file d’attente monte.
ZFS est rarement le méchant. C’est l’auditeur.
Faites ceci ensuite :
- Retestez avec fio en utilisant direct I/O à plusieurs profondeurs de file d’attente et assez longtemps pour atteindre l’état stable.
- Capturez iostat et zpool iostat pendant le ralentissement et décidez si le goulot est la saturation du périphérique, la latence sync, ou le CPU/interrupts.
- Vérifiez la marge du pool et l’ashift ; si vous êtes trop plein ou mal aligné, corrigez le design, pas les symptômes.
- Si le sync est le problème, résolvez-le correctement : SLOG PLP, meilleurs SSD, ou acceptez que la durabilité a un coût.
- Résistez aux tunings aléatoires. Tuner seulement après avoir expliqué quelle file se remplit et pourquoi.
ZFS est un système pour les personnes qui préfèrent la réalité aux impressions. Si vous voulez des impressions, achetez un benchmark marketing et encadrez-le.