Votre pool ZFS « passe les benchmarks » jusqu’au jour où vous devez streamer quelques téraoctets — lecture de médias, sauvegardes, scans analytiques, réhydratation d’un store d’objets — et le débit
s’effondre en motif en dents de scie. Le CPU semble inactif. Les disques semblent occupés. Le réseau accuse le stockage, le stockage accuse le réseau, et quelqu’un propose d’ajouter
plus de RAM comme si c’était de l’eau bénite.
C’est là que les lectures séquentielles sur ZFS deviennent intéressantes : ZFS peut être brutalement rapide en streaming, mais c’est aussi un système de fichiers avec des opinions arrêtées, plusieurs caches,
des sommes de contrôle partout, et un modèle transactionnel qui transforme parfois le “simple” en “complexe avec style”. Réglons-le comme si nous gérions de vrais systèmes de production.
Ce que signifient les « lectures séquentielles » sur ZFS (et ce qu’elles ne signifient pas)
« Lecture séquentielle » décrit une charge de travail, pas une garantie. Sur disques tournants, les lectures séquentielles signifient de longues régions contiguës sur le disque, peu de seeks et de gros I/O.
Sur SSD, cela signifie surtout de gros I/O et une profondeur de file élevée sans petites lectures aléatoires qui polluent le pipeline.
Sur ZFS, les lectures séquentielles sont façonnées par trois couches de réalité :
- Séquentialité logique : votre application lit les offsets de fichier dans l’ordre.
- Agencement sur disque : les blocs peuvent ne pas être physiquement contigus à cause du copy-on-write et de la fragmentation de l’espace libre.
- Comportement I/O de ZFS : recordsize, prélecture, vérification des sommes de contrôle, compression et mise en cache décident combien et quel type d’I/O vous allez réellement émettre.
Vous pouvez avoir une lecture applicative parfaitement séquentielle qui devient quand même « semi-aléatoire » sur disque parce que le fichier a été réécrit pendant des mois,
des snapshots ont épinglé d’anciens blocs, et l’espace libre est devenu confetti. Ce n’est pas que ZFS est mauvais ; c’est ZFS qui est honnête sur la physique.
Votre objectif pour un débit de streaming maximal est de faire en sorte que ZFS émette des lectures larges, garde la file assez profonde pour saturer les périphériques,
évite un churn inutile du cache et s’assure que le CPU n’est pas le point d’étranglement caché. Les pools les plus rapides ne sont pas ceux avec le plus de réglages ; ce sont ceux avec le moins de surprises.
Faits et historique qui comptent en pratique
- ZFS est né chez Sun Microsystems au milieu des années 2000 avec des sommes de contrôle end-to-end comme fonctionnalité de base. Cette vérification n’est pas un « surcoût » ; c’est le design.
- Le pitch original de ZFS incluait « no fsck » — un grand avantage opérationnel. Pour les lectures en streaming, cela signifie aussi que l’intégrité des métadonnées est protégée en permanence, pas occasionnellement.
- Le copy-on-write explique pourquoi les snapshots sont peu coûteux — et aussi pourquoi les datasets de longue durée peuvent se fragmenter. Le débit de streaming se dégrade souvent avec le temps si vous réécrivez de gros fichiers in place.
- « 128K blocks » est devenu une norme culturelle parce que recordsize=128K fonctionne bien pour beaucoup de charges séquentielles. Ce n’est pas magique ; c’est juste un bon compromis par défaut.
- L2ARC a été introduit pour étendre le cache vers les SSD quand la RAM était chère. Il aide davantage les lectures aléatoires que le streaming soutenu parce que les lectures en streaming ont tendance à être « lues une fois ».
- zfs send/receive a remodelé les flux de sauvegarde en rendant la réplication consciente des blocs. C’est aussi un générateur de charge de lecture séquentielle qui peut exposer les limites de bande passante du pool très rapidement.
- OpenZFS a unifié plusieurs forks donc les recommandations de tuning ne sont plus que du folklore « Solaris-only », mais les valeurs par défaut diffèrent encore selon les plateformes et versions.
- ZFS moderne propose des classes d’allocation spéciales (special vdev) pour séparer métadonnées/petits blocs. Cela peut indirectement améliorer le streaming en réduisant la contention sur les métadonnées.
- Les algorithmes de somme de contrôle ont évolué (fletcher4, sha256, etc.). Les hashes plus forts coûtent du CPU ; les hashes rapides coûtent moins. Le streaming peut devenir lié au CPU avant que vous ne le remarquiez.
Le chemin des lectures en streaming : où le débit meurt
Si vous voulez un débit maximal, vous devez savoir quelle étape vous limite. Une lecture séquentielle sur ZFS suit typiquement ce flux :
- L’application émet des lectures (souvent 4K–1M selon l’app/bibliothèque).
- La DMU mappe les offsets de fichier aux blocs en fonction de recordsize et des tailles de blocs réelles sur disque.
- La prélecture décide s’il faut lire en avance de façon spéculative.
- Recherche dans l’ARC hit ou miss ; les misses déclenchent des I/O disque.
- Le planificateur vdev transforme les lectures logiques en lectures physiques à travers mirrors/RAIDZ, en respectant les limites de file.
- Le périphérique complète les lectures ; les données sont vérifiées par somme de contrôle, décompressées si nécessaire, puis placées dans l’ARC et copiées vers l’espace utilisateur.
Le débit en streaming meurt généralement à l’un des quatre endroits suivants :
- Bande passante du périphérique (vous n’avez tout simplement pas assez de spindles, de lanes ou de bande passante SSD).
- Taille d’I/O trop petite (beaucoup d’overhead par octet ; vous « gagnez » sur les IOPS et perdez sur les MB/s).
- CPU saturé par les sommes de contrôle/la décompression (surtout avec des pools NVMe rapides).
- Fragmentation et géométrie RAIDZ (plus d’opérations I/O que prévu, coalescence de lecture cassée, ou coût de calcul de parité).
Blague n°1 : Si vos « lectures séquentielles » ressemblent à de l’aléatoire, félicitations — vous avez inventé une nouvelle catégorie de benchmark : « stockage interprétatif ».
Mode d’emploi de diagnostic rapide (premier/deuxième/troisième)
Premier : prouver ce qui est saturé
- Vérifiez le débit et la latence par vdev avec
zpool iostat -v. Si un vdev est saturé alors que les autres sont inactifs, vous avez un problème d’agencement ou de queueing. - Vérifiez le CPU (user/system, softirqs) pendant le stream. Si le CPU monte alors que le débit plafonne, les sommes de contrôle/la compression ou la gestion des IRQ peuvent limiter.
- Vérifiez le réseau si c’est distant. Un « problème de stockage » qui plafonne exactement à 9,4 Gbps est souvent un problème réseau habillé en stockage.
Deuxième : valider la taille d’I/O et le comportement de prélecture
- Regardez recordsize du dataset et si les fichiers ont été écrits avec. Les anciens fichiers conservent de vieilles tailles de bloc.
- Observez les tailles de lecture réelles via
zpool iostatetfio. Si vous voyez beaucoup de lectures 4K–16K, vous payez la taxe d’overhead. - Confirmez que la prélecture n’est pas désactivée (paramètres du module) et qu’elle n’est pas contrecarrée par des motifs d’accès (par ex. de nombreux lecteurs avec accès entrelacé).
Troisième : inspecter la santé du pool et la contention « d’arrière-plan »
- Scrub/resilver en cours peut fortement réduire la bande passante de streaming. Idem pour une suppression massive de snapshots (libération d’espace intense).
- Erreurs ou périphériques lents provoquent des retries et gonflent la latence ; les mirrors choisiront souvent le côté « plus rapide », mais si les deux sont en difficulté vous le verrez.
- Espace et fragmentation : un pool à 85–90% est rarement un champion du streaming. ZFS a besoin d’espace de manœuvre.
Tâches pratiques : commandes, sorties, décisions
Voici les tâches que j’exécute réellement quand quelqu’un dit « les lectures séquentielles ZFS sont lentes ». Chaque élément contient : la commande, ce que signifie la sortie, et la décision suivante.
Hypothèses : Linux + outils OpenZFS ; adaptez les chemins et noms de pool.
Task 1: Identify pool topology and RAID level (you can’t tune what you don’t understand)
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:11:33 with 0 errors on Wed Dec 18 03:21:39 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Signification : Vous êtes sur un seul vdev RAIDZ2 de six disques. Les lectures en streaming seront limitées par la bande passante agrégée de ce vdev et le comportement RAIDZ.
Un gros vdev est une seule « voie » du point de vue de ZFS.
Décision : Si vous avez besoin de plus de débit, ajoutez des vdevs (plus de voies) ou passez à des mirrors pour plus de parallélisme. Le tuning ne créera pas de bande passante ex nihilo.
Task 2: See real-time read throughput, IOPS, and latency per vdev and disk
cr0x@server:~$ sudo zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
------------------------------------------ ----- ----- ----- ----- ----- -----
tank 8.11T 2.77T 480 5 820M 1.20M
raidz2-0 8.11T 2.77T 480 5 820M 1.20M
sda - - 85 1 135M 256K
sdb - - 76 1 130M 256K
sdc - - 79 1 138M 256K
sdd - - 80 1 140M 256K
sde - - 78 1 139M 256K
sdf - - 82 0 138M 0K
------------------------------------------ ----- ----- ----- ----- ----- -----
Signification : Vous obtenez ~820 MB/s en lecture, répartis équitablement. C’est plausible proche du plafond séquentiel de ces disques.
Si vous attendiez 2–3 GB/s, la topologie explique la différence.
Décision : Si le pool semble uniformément chargé et le débit « raisonnable », arrêtez de blâmer ZFS et commencez la planification de capacité. Si un disque traîne, enquêtez.
Task 3: Confirm dataset settings that affect streaming reads
cr0x@server:~$ sudo zfs get -o name,property,value -s local,received recordsize,compression,atime,primarycache,secondarycache tank/media
NAME PROPERTY VALUE
tank/media recordsize 1M
tank/media compression lz4
tank/media atime off
tank/media primarycache all
tank/media secondarycache all
Signification : recordsize est 1M (bon pour gros fichiers en streaming), compression est lz4 (généralement bon), atime est off (bien ; évite du trafic d’écriture lors des lectures).
Décision : Si recordsize est 128K mais que vous stockez de gros fichiers, envisagez 1M pour ce dataset avant d’ingérer les données. Si vous avez déjà des données, il faudra réécrire/replicater pour en bénéficier.
Task 4: Verify what block sizes files actually have (not what you wish they had)
cr0x@server:~$ sudo zdb -ddddd tank/media | head -n 20
Dataset tank/media [ZPL], ID 52, cr_txg 11423, 2.31T, 98123 objects
Object lvl iblk dblk dsize dnsize lsize %full type
17 1 128K 1M 1.00M 512B 4.00M 100.00 ZFS plain file
18 1 128K 128K 128.0K 512B 512.0K 100.00 ZFS plain file
Signification : Certains fichiers utilisent des blocs de 1M, d’autres 128K. recordsize est une borne supérieure ; les données existantes peuvent être plus petites selon la manière dont elles ont été écrites.
Décision : Si vos objets clés de streaming n’utilisent pas de grands blocs, planifiez une réécriture : zfs send|recv, rsync sans reflinks, ou ré-ingestion côté application.
Task 5: Measure raw sequential read bandwidth at the file level (bypass “the app is weird”)
cr0x@server:~$ fio --name=seqread --filename=/tank/media/bigfile.bin --rw=read --bs=1M --iodepth=32 --direct=1 --numjobs=1 --time_based --runtime=30
seqread: (g=0): rw=read, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libaio, iodepth=32
fio-3.36
Starting 1 process
seqread: Laying out IO file (1 file / 0MiB)
Jobs: 1 (f=1): [R(1)][100.0%][r=1050MiB/s][r=1050 IOPS][eta 00m:00s]
seqread: (groupid=0, jobs=1): err= 0: pid=21944: Thu Dec 26 11:08:14 2025
read: IOPS=1048, BW=1048MiB/s (1099MB/s)(30.7GiB/30005msec)
clat (usec): min=310, max=2200, avg=720.12, stdev=120.44
Signification : Avec I/O direct, blocs 1M et iodepth raisonnable, vous obtenez ~1.0 GiB/s. C’est proche du débit observé côté vdev.
Décision : Si fio est rapide mais que l’application est lente, le goulot est le comportement applicatif (petites lectures, mono-thread, points de synchronisation). Si fio est lent, continuez l’investigation côté stockage.
Task 6: Verify ARC size and hit ratios (streaming is often miss-heavy, and that’s fine)
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
11:09:01 820M 790M 96 790M 96 0 0 0 0 42G 64G
11:09:02 835M 810M 97 810M 97 0 0 0 0 42G 64G
11:09:03 810M 785M 96 785M 96 0 0 0 0 42G 64G
Signification : Le taux de miss ARC est élevé pendant un stream. C’est normal : le streaming est « lire et passer à autre chose ».
arcsz est 42G avec cible c=64G, donc l’ARC est sain.
Décision : Ne paniquez pas et n’« augmentez » pas l’ARC simplement parce que les misses sont élevés. L’ARC aide les relis ; le débit en streaming est généralement limité par la bande passante des périphériques.
Task 7: Check whether prefetch is working or disabled at module level
cr0x@server:~$ cat /sys/module/zfs/parameters/zfs_prefetch_disable
0
Signification : 0 signifie que la prélecture est activée globalement.
Décision : Si c’est 1 et que votre charge est majoritairement séquentielle, remettez-le à 0 (et trouvez qui l’a désactivé et pourquoi).
Task 8: Check device-level saturation and queue behavior
cr0x@server:~$ iostat -x 1 3
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz aqu-sz %util
sda 85.0 138240.0 0.0 0.00 8.40 1626.4 0.71 98.0
sdb 76.0 133120.0 0.0 0.00 8.10 1751.6 0.62 97.2
sdc 79.0 141312.0 0.0 0.00 8.55 1788.8 0.68 98.5
sdd 80.0 143360.0 0.0 0.00 8.60 1792.0 0.69 98.7
sde 78.0 142336.0 0.0 0.00 8.45 1824.8 0.66 98.3
sdf 82.0 141312.0 0.0 0.00 8.50 1723.3 0.70 98.6
Signification : %util proche de 100% et await ~8–9ms indiquent que les disques sont saturés. rareq-sz est grand (~1.6–1.8MB), ce qui est bon pour le streaming.
Décision : Si les périphériques sont saturés, le tuning au-dessus du niveau vdev n’aidera pas. Ajoutez des spindles, ajoutez des vdevs, ou migrez vers SSD/NVMe.
Task 9: Confirm you’re not fighting a scrub/resilver (silent throughput killers)
cr0x@server:~$ sudo zpool status tank | sed -n '1,12p'
pool: tank
state: ONLINE
scan: scrub in progress since Thu Dec 26 10:41:12 2025
2.11T scanned at 1.20G/s, 1.02T issued at 595M/s, 8.11T total
0B repaired, 12.59% done, 03:56:18 to go
Signification : Le scrub consomme ~595 MB/s de bande passante émise. Vos lectures en streaming se battent pour les mêmes disques.
Décision : Si c’est une fenêtre de streaming en production, mettez le scrub en pause/annulez-le ou planifiez-le correctement. Les scrubs sont bons ; pas pendant les pics.
Task 10: Check ashift and sector alignment (bad alignment is forever)
cr0x@server:~$ sudo zdb -C tank | grep -E 'ashift|vdev_tree' -n | head -n 8
45: vdev_tree:
61: ashift: 12
Signification : ashift=12 signifie secteurs 4K, ce qui est correct pour la plupart des HDD/SSD modernes. Si vous voyez ashift=9 sur des disques 4K, les performances peuvent en souffrir gravement.
Décision : Si ashift est incorrect, la solution consiste à reconstruire le vdev correctement. Il n’existe pas de « réglage » qui annule les douleurs d’un mauvais alignement.
Task 11: Evaluate fragmentation and space pressure (sequential reads hate a packed pool)
cr0x@server:~$ sudo zpool list -o name,size,alloc,free,capacity,fragmentation tank
NAME SIZE ALLOC FREE CAPACITY FRAG
tank 10.9T 8.11T 2.77T 74% 33%
Signification : 74% plein est acceptable ; 33% de fragmentation est modéré. Si la capacité est à 90% et que la frag est élevée, le « séquentiel » dérivera vers de l’aléatoire.
Décision : Si vous êtes au-dessus de ~80–85% sur un pool qui doit streamer, planifiez une expansion ou une migration. Si la fragmentation est élevée, envisagez de réécrire les datasets ou de restaurer depuis une réplication pour recompacter les blocs.
Task 12: Check per-dataset primarycache/secondarycache (stop caching what you won’t reread)
cr0x@server:~$ sudo zfs get -o name,property,value primarycache,secondarycache tank/backup
NAME PROPERTY VALUE
tank/backup primarycache metadata
tank/backup secondarycache none
Signification : Ce dataset ne met en cache que les métadonnées et évite L2ARC. C’est souvent correct pour des scans de sauvegarde en une passe et des lectures séquentielles massives.
Décision : Si les workloads de streaming expulsent du cache utile pour d’autres services, définissez les datasets de streaming sur primarycache=metadata. Ne traitez pas l’ARC comme un buffet illimité.
Task 13: Validate that readahead isn’t sabotaging you at the Linux block layer
cr0x@server:~$ lsblk -o NAME,TYPE,RA,MOUNTPOINT | grep -E 'tank|zd|sd[a-z]'
sda disk 256
sdb disk 256
sdc disk 256
sdd disk 256
sde disk 256
sdf disk 256
Signification : La readahead ici est 256 (unités KiB dans de nombreuses distributions). ZFS fait sa propre prélecture ; la readahead Linux importe surtout pour les systèmes non-ZFS.
Pourtant, des valeurs bizarres (comme plusieurs mégaoctets par disque) peuvent provoquer des I/O gaspillées.
Décision : Si quelqu’un a réglé la readahead aveuglément et que c’est massif, ramenez-la à des valeurs sensées. Réglez une couche à la fois.
Task 14: Confirm your stream isn’t secretly a tiny-read workload
cr0x@server:~$ sudo zpool iostat -r tank 1 2
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 8.11T 2.77T 8500 3 420M 1.00M
---------- ----- ----- ----- ----- ----- -----
tank 8.11T 2.77T 8600 2 430M 1.10M
---------- ----- ----- ----- ----- ----- -----
Signification : 8.5K ops de lecture pour ~420 MB/s implique une taille I/O moyenne d’environ ~50 KB, pas idéal pour du « streaming ».
Décision : Si votre taille d’I/O est petite, corrigez l’application pour augmenter la taille de lecture/la profondeur de file ; augmentez recordsize pour les futurs écrits ; et vérifiez que la prélecture n’est pas perturbée par de nombreux lecteurs entrelacés.
Leviers de réglage qui font réellement bouger le débit
1) recordsize: set it for the files you will store, not the ones you already stored
recordsize fixe la taille maximale de bloc que ZFS utilisera pour les fichiers dans un dataset. Pour les lectures séquentielles, des blocs plus grands signifient généralement moins d’opérations I/O,
moins de calculs de somme de contrôle par octet, moins de consultations de métadonnées et une meilleure efficacité des périphériques.
Que faire :
- Médias, sauvegardes, gros objets, scans analytiques :
recordsize=1Mest souvent le bon choix de départ. - Bases de données et images VM : ne montez pas recordsize aveuglément. Ces workloads sont souvent mixtes/hasardeux ; optimisez-les séparément.
L’astuce : recordsize ne réécrit pas rétroactivement les fichiers existants. Si votre dataset de streaming a été créé avec 128K et alimenté pendant un an, passer à 1M aujourd’hui n’aidera que les nouvelles écritures.
Si vous avez besoin du bénéfice maintenant, réécrivez les données.
2) atime: turn it off for streaming reads unless you enjoy unnecessary writes
Les mises à jour atime lors des lectures causent des écritures. Les écritures entraînent du travail TXG et potentiellement une activité disque supplémentaire.
Pour un dataset dédié aux lectures en streaming, atime=off est une victoire sans surprise.
3) primarycache / secondarycache: stop poisoning ARC with one-pass streams
L’ARC est précieux car il est en RAM et il est chaud. Les lectures séquentielles de gros datasets peuvent expulser du cache réellement utile pour d’autres services (métadonnées, petits fichiers chauds,
blobs de configuration fréquemment lus, etc.).
Pour les datasets principalement en lecture one-pass (vérification de sauvegarde, réhydratation d’archives, analytics batch), mettez :
primarycache=metadata. Souvent aussi secondarycache=none si vous avez L2ARC et ne voulez pas le brûler sur des données jetables.
Cela n’augmente pas nécessairement le débit du stream ; cela évite des dommages collatéraux. Dans les systèmes réels, c’est déjà la moitié de la bataille.
4) Compression: lz4 is usually “free,” until it isn’t
compression=lz4 améliore souvent le débit de lecture en streaming parce que vous lisez moins d’octets sur disque et dépensez un peu de CPU pour décompresser.
C’est un excellent compromis sur des pools HDD et beaucoup de pools SSD.
Mais sur NVMe rapides, la compression peut déplacer le goulot vers le CPU. Vous verrez des périphériques sous-utilisés et des threads CPU saturés par la décompression et les sommes de contrôle.
Si votre pipeline est lié au CPU, envisagez des CPU plus rapides, vérifiez que vous n’utilisez pas une somme de contrôle coûteuse, et mesurez avec la compression activée/désactivée pour vos données.
5) Don’t confuse “more ARC” with “more throughput”
L’ARC aide quand vous relisez des données. Le débit en streaming est généralement limité par la bande passante de stockage et par l’efficacité avec laquelle ZFS émet des I/O.
Augmenter l’ARC peut aider si votre stream boucle ou si le caching des métadonnées est le limiteur caché, mais pour des lectures en une passe cela change souvent juste qui garde la RAM.
6) Parallelism: one vdev is one lane
Les pools ZFS augmentent le débit principalement en ajoutant des vdevs. Les mirrors fournissent généralement un meilleur parallélisme de lecture et une géométrie plus simple.
RAIDZ peut être efficace en bande passante et en capacité, mais un seul vdev RAIDZ reste une seule voie, ce qui limite la concurrence.
7) Special vdev: metadata belongs on fast storage (sometimes)
Si votre job de lecture séquentielle bute encore sur les métadonnées (beaucoup de fichiers, beaucoup de parcours de répertoires, petits fichiers annexes), déplacer les métadonnées et petits blocs vers un special vdev
peut réduire le blocage en tête de file sur HDD. Il s’agit davantage du « temps jusqu’au premier octet » et d’un streaming plus régulier dans les workloads riches en fichiers que du MB/s brut sur un grand fichier.
Blague n°2 : L2ARC pour le streaming, c’est comme emmener une valise pour une nuit — techniquement impressionnant, pratiquement inutile.
Agencement vdev et calculs de bande passante à défendre en réunion
Le tuning des lectures séquentielles devient existentiel quand on demande : « Pourquoi ce pool à 12 disques ne peut-il pas atteindre 4 GB/s ? » Parce que la topologie compte plus que l’optimisme.
Mirrors : le choix ennuyeux mais haut débit
Les mirrors lisent depuis soit l’un soit l’autre côté. Avec plusieurs vdevs mirror, ZFS peut répartir les lectures à travers les vdevs et les disques. Pour les grandes lectures en streaming, les mirrors offrent généralement :
- un haut degré de concurrence (beaucoup de vdevs)
- des performances prévisibles sous charge mixte
- un comportement de rebuild simple (resilver clair)
Le compromis est l’efficacité de capacité. Les ingénieurs stockage peuvent en discuter pendant des heures, ce qui est une forme reconnue de cardio dans certaines organisations.
RAIDZ : efficace en capacité, mais sensible à la géométrie
RAIDZ peut streamer vite, surtout avec plusieurs vdevs RAIDZ, mais deux réalités pratiques existent :
- Goulot d’un vdev unique : Un vdev RAIDZ unique est une seule voie. Si votre pool a un seul vdev RAIDZ2, vous êtes limité à l’enveloppe de performance de ce vdev.
- Les petites lectures coûtent plus : RAIDZ doit reconstruire à partir de la parité pour certains motifs d’accès, et les petits blocs peuvent créer une amplification de lecture.
Pour un débit séquentiel maximal, privilégiez plusieurs vdevs de taille adaptée à vos contraintes opérationnelles. Si vous ne pouvez pas ajouter de vdevs parce que le châssis est plein,
vos options de « tuning » consistent principalement à ne pas aggraver la situation.
Wide vdevs : séduisants sur les feuilles de calcul, compliqués en production
Les très larges vdevs RAIDZ semblent excellents sur le rapport capacité/prix. Ils augmentent aussi les temps de rebuild, la fenêtre d’exposition, et peuvent créer des falaises de performance quand un disque est lent.
Si votre activité principale est le débit de streaming et les opérations prévisibles, les vdevs larges sont une négociation avec l’entropie.
Profondeur de file et concurrence : le streaming est un pipeline, pas une requête unique
Beaucoup d’applications lisent séquentiellement mais mono-thread avec des buffers petits. Cela peut laisser le pool sous-utilisé parce que les disques/SSDs veulent plusieurs I/O en attente.
Quand fio avec iodepth=32 atteint 1.5 GB/s mais que votre application atteint 400 MB/s, l’application se bride elle-même.
Corrigez cela en augmentant la taille de lecture de l’application, en activant l’I/O asynchrone, en ajoutant des threads lecteurs, ou en utilisant des outils qui lisent de grands blocs efficacement.
ZFS peut prélecture, mais ce n’est pas un substitut à une application qui refuse de mettre des requêtes en file.
Compression, sommes de contrôle et CPU : amis jusqu’à preuve du contraire
ZFS fait des sommes de contrôle end-to-end. Ce n’est pas optionnel. La bonne nouvelle : la vérification des sommes est généralement assez rapide sur les CPU modernes.
La mauvaise nouvelle : le « généralement » s’arrête dès que vous passez à des NVMe rapides tout en gardant le même CPU d’il y a trois ans.
Comment savoir si vous êtes lié au CPU sur les lectures
- zpool iostat montre des périphériques non saturés mais le débit plafonne.
- mpstat/top montre un ou plusieurs cœurs CPU saturés en temps kernel/system.
- fio avec I/O direct n’augmente pas le débit quand vous augmentez l’iodepth au-delà d’un certain point.
Compromis de la compression
lz4 est la recommandation par défaut pour une bonne raison : faible coût CPU, souvent meilleur débit, et amélioration du cache effectif.
Si vos données sont incompressibles (vidéo déjà compressée), lz4 n’aidera pas beaucoup ; en général cela ne nuit pas non plus, mais mesurez.
Une compression plus forte (zstd à hauts niveaux) peut réduire les I/O disque au prix du CPU. Cela peut aider les pools HDD pour certains datasets, mais pour le débit de streaming pur,
il est facile d’en faire trop et de déplacer le goulot vers le CPU. « Plus de compression » n’est pas synonyme de « plus de performance ».
Choix d’algorithme de somme de contrôle
La plupart des déploiements utilisent fletcher4 (rapide) ou sha256 (plus robuste, plus coûteux). Pour le débit de lecture, des sommes rapides peuvent compter sur les systèmes NVMe.
Si vous êtes dans un environnement réglementé, le choix peut être imposé. Sinon, choisissez pragmatiquement : gardez l’intégrité suffisante et la performance prévisible.
Une citation qui tient en opérations : « L’espoir n’est pas une stratégie. »
— General Gordon R. Sullivan.
Vous ne réparez pas le débit de lecture par l’espoir ; vous le réparez par des mesures et des changements contrôlés.
Prélecture, ARC et pourquoi L2ARC ne sauvera pas votre stream
Prélecture : ce qu’elle apporte aux lectures séquentielles
La prélecture ZFS tente de détecter les accès séquentiels et d’émettre des I/O en avance pour que les blocs suivants soient déjà en transit.
Pour une lecture d’un seul gros fichier de manière séquentielle, la prélecture est généralement bénéfique. Pour de nombreux lecteurs séquentiels entrelacés, elle peut devenir bruyante mais reste utile.
Le mode d’échec classique : quelqu’un désactive la prélecture pour « corriger la latence des lectures aléatoires » sur un dataset de base de données, puis oublie que c’est global ou oublie qu’il l’a changé,
et maintenant les streams médias ou les restaurations de sauvegarde sont plus lentes. Cela arrive plus souvent qu’on ne le reconnaît.
ARC : quoi mettre en cache pour les systèmes de streaming
L’ARC est un cache combiné données+métadonnées. Pour les workloads de streaming, mettre en cache les données du stream lui-même apporte rarement un bénéfice sauf si vous relisez.
Ce qui importe : les métadonnées. Si votre workload ouvre de nombreux fichiers, fait beaucoup d’appels stat, traverse des répertoires, ou lit des index annexes,
la mise en cache des métadonnées peut améliorer le « ramp-up » et lisser les performances.
L2ARC : quand cela aide
L2ARC est un cache de second niveau, généralement sur SSD. Il aide quand votre working set est plus grand que la RAM et est relu.
Les lectures séquentielles de gros fichiers sont rarement relues assez rapidement pour justifier L2ARC ; il peut aussi ajouter du surcoût car ZFS doit gérer des en-têtes L2ARC et alimenter le cache.
Si votre système est multi-tenant et que les jobs de streaming expulsent les données chaudes d’autres locataires, L2ARC peut aider ces autres locataires,
mais il n’accélérera pas nécessairement le job de streaming. C’est un gain honnête, mais soyez honnête sur le gain que vous achetez.
Scrub/resilver et autres jobs « d’arrière-plan » qui ne le sont pas
Les lectures en streaming se concurrencent avec tout ce qui veut de la bande passante disque : scrub, resilver, suppression de snapshots, fort churn de métadonnées, et parfois même des SMART long tests
si votre contrôleur et le firmware des disques les gèrent mal.
Règles opérationnelles qui gardent le streaming prévisible
- Planification des scrubs : lancez les scrubs quand vous pouvez accepter la perte de bande passante. Si vous ne trouvez pas de fenêtre, votre planification de capacité vous ment.
- Posture de resilver : traitez le mode dégradé comme un incident. Le débit de streaming pendant un resilver est souvent réduit, et c’est attendu.
- Suppression de snapshots : les destructions massives peuvent provoquer une activité intense d’espace libre. Ne faites pas ça à 10:00 un lundi.
Trois mini-histoires d’entreprise issues du terrain
Incident causé par une mauvaise hypothèse : « C’est séquentiel, donc ça doit être contigu »
Une équipe pipeline média avait un NAS sur ZFS servant de gros fichiers vidéo. Pendant des mois tout allait bien : les monteurs récupéraient des rushes, les nœuds de rendu lisaient les clips,
et le débit restait confortable. Puis une nouvelle production est arrivée et tout est devenu « collant ». Lecture saccadée. Les transcodages de batch ont pris la nuit et n’ont toujours pas fini au matin.
L’hypothèse était simple : « Les fichiers sont gros et lus séquentiellement, donc les disques font des lectures séquentielles. » La vérité était plus crue.
Le dataset avait subi un churn constant : ingestion, éditions partielles, ré-exports fréquents, et snapshots réguliers pour « sécurité ».
Les fichiers étaient réécrits par l’application, mais le copy-on-write de ZFS a transformé chaque réécriture en nouvelles allocations de blocs.
En regardant zpool list, le pool était dans la fin des 80% de capacité et la fragmentation était suffisamment élevée pour impacter.
zpool iostat montrait beaucoup de lectures plutôt petites et une latence plus importante que prévu pour les mêmes disques.
La charge était séquentielle dans l’esprit de l’application mais pas physiquement séquentielle sur disque.
La solution n’était pas un sysctl magique. Ils ont étendu le pool en ajoutant des vdevs, puis ont répliqué le dataset vers un dataset neuf avec le recordsize voulu.
Cette réécriture a effectivement « défragmenté » les données. Le débit est revenu. La leçon : les accès séquentiels applicatifs ne garantissent pas un accès séquentiel sur disque,
surtout après des mois de snapshots et de réécritures.
Optimisation contre-productive : « Désactiver la prélecture pour réduire la pollution du cache »
Un groupe plateforme gérait une flotte mixte : bases de données, stockage d’objets et service de sauvegarde sur un stockage ZFS partagé.
Quelqu’un avait lu que la prélecture pouvait nuire à la latence des lectures aléatoires, surtout pour les bases de données qui font leur propre caching.
Ils ont désactivé la prélecture au niveau du module pour « stabiliser la BD ».
L’équipe BD a constaté une amélioration pendant les pics. Tout le monde a célébré discrètement et est passé à autre chose.
Deux semaines plus tard, un test de restauration a été exécuté. Le débit a fortement chuté. Une autre équipe effectuant des scans analytiques a vu la même chose.
Les symptômes étaient classiques : le pool n’émettait plus de pipelines de lecture larges et fluides ; il lorgnait des lectures à la demande.
Le rapport d’incident était gênant : personne n’avait relié la nature globale du paramètre de prélecture à la variété des workloads.
L’« optimisation » a résolu une douleur en en injectant une autre ailleurs.
Nous avons réactivé la prélecture et traité le comportement BD de la bonne manière : choix par dataset, réglages applicatifs, et isolation des workloads quand nécessaire.
La morale large : « le tuning global » est un euphémisme pour « rayon d’impact global ». Quand vous changez le comportement du système de fichiers, vous le changez pour tout le monde.
Pratique ennuyeuse mais correcte qui a sauvé la mise : « Nous avons benchmarké le plan de rebuild »
Un projet de refresh stockage a migré une plateforme backup/restore vers de nouveaux serveurs avec NIC plus rapides et plus de SSD.
L’équipe a fait quelque chose d’impopulaire : elle a documenté le débit attendu par vdev, par hôte et par chemin réseau, puis testé chaque couche indépendamment avec des outils simples.
Ce n’était pas glamour, mais c’était mesurable.
Pendant la semaine de cutover, un nœud sous-performait. La panique a failli démarrer : « ZFS est lent » et « peut-être un firmware défectueux ».
Mais comme des valeurs de base existaient, l’équipe a immédiatement comparé le zpool iostat -v du nœud avec les autres.
Un SSD montrait une latence légèrement plus élevée et une bande passante plus basse. Pas catastrophique, juste suffisant pour brider le nœud.
Ils ont remplacé le périphérique suspect, resilveré, et le débit a rejoint la baseline.
Pas de tuning héroïque. Pas de roulette sysctl en pleine nuit. Juste une validation ennuyeuse et une enveloppe de performance convenue d’avance.
Le gain n’était pas seulement la vitesse ; c’était la confiance. Quand vous savez ce qu’est le « normal », vous traitez les écarts comme des faits, pas des impressions.
Erreurs courantes : symptôme → cause racine → correction
1) Symptom: Throughput is capped far below disk specs, and iostat shows small average read sizes
Root cause: Application is reading in small chunks (4K–64K), defeating efficient streaming; or files are stored in small blocks due to recordsize at write time.
Fix: Increase application read size/queue depth; set recordsize=1M for the dataset and rewrite data to benefit; verify prefetch enabled.
2) Symptom: One disk in a vdev shows higher await and lower bandwidth, pool throughput sawtooths
Root cause: A slow or failing device, cabling/controller issues, or SMR drive behavior under sustained load.
Fix: Confirm with zpool iostat -v and iostat -x; replace the device; validate firmware/controller; avoid SMR for performance tiers.
3) Symptom: Streaming is fine until scrub starts, then everything drops
Root cause: Scrub competes for bandwidth; scheduling ignores peak usage windows.
Fix: Reschedule scrubs; consider per-pool policy; temporarily pause/cancel during critical streams; plan more headroom.
4) Symptom: ARC hit rate is low during stream, and someone calls it a “cache problem”
Root cause: Streaming is miss-heavy by nature; ARC isn’t failing.
Fix: Stop tuning based on miss% alone; focus on disk saturation and I/O size; protect ARC via primarycache=metadata where appropriate.
5) Symptom: NVMe pool not saturating devices, CPU is high, throughput plateaus
Root cause: CPU-bound on checksum verification and/or decompression; possibly single-threaded readers.
Fix: Benchmark with compression on/off; ensure enough parallelism (jobs/iodepth); consider faster CPU, NUMA pinning strategies at the application level, and avoid heavy compression levels.
6) Symptom: “We changed recordsize but nothing improved”
Root cause: Existing files retain their block sizes; recordsize isn’t retroactive.
Fix: Rewrite data: replication to a fresh dataset, re-ingest, or application rewrite. Validate with zdb.
7) Symptom: Pool got slower over months without hardware changes
Root cause: Fragmentation and high capacity due to CoW + snapshots + rewrite churn.
Fix: Keep pools below ~80–85% for performance tiers; add vdevs; migrate/replicate to re-pack; revisit snapshot retention.
Listes de contrôle / plan étape par étape
Step-by-step: tune a dataset for maximum streaming reads (new data)
- Create a dedicated dataset for streaming objects; don’t share with databases/VMs.
- Set recordsize (typically
1Mfor large files):zfs set recordsize=1M tank/media. - Set atime off:
zfs set atime=off tank/media. - Use lz4 compression unless you’ve proven it hurts:
zfs set compression=lz4 tank/media. - Decide caching policy: for one-pass workloads,
primarycache=metadata; for shared read-hot libraries, keepall. - Ingest data once (avoid rewrite churn); validate block sizes with
zdb. - Benchmark with fio using realistic block sizes and iodepth; capture
zpool iostat -vduring the test.
Step-by-step: recover streaming throughput on an existing “slow” dataset
- Run the fast diagnosis playbook and determine if you’re device-bound, CPU-bound, or I/O-size-bound.
- Check pool capacity and fragmentation; if you’re too full, expand or migrate first.
- Confirm actual block sizes of the important files; don’t assume recordsize changed anything.
- Stop background contention during testing (scrub/resilver/snapshot destruction).
- Rewrite the dataset if block sizes/fragmentation are the issue: replicate to a fresh dataset with correct settings.
- Re-test with fio; compare per-vdev metrics and CPU utilization before/after.
Operational checklist: keep streaming performance from degrading
- Keep performance pools below ~80–85% capacity if you care about consistent bandwidth.
- Schedule scrubs outside streaming windows; treat scrub overlap as a planned performance reduction.
- Avoid mixing workloads with incompatible tuning goals on the same dataset.
- Baseline throughput after changes; keep one “known-good” benchmark procedure.
- When changing global module parameters, document and review them like you would firewall rules.
FAQ
1) Should I set recordsize=1M everywhere to get better sequential reads?
Non. Réglez-le sur les datasets qui stockent de gros fichiers adaptés au streaming. Bases de données, images VM et workloads mixtes aléatoires peuvent empirer avec des blocs surdimensionnés.
2) Why didn’t changing recordsize improve my existing files?
Parce que recordsize ne réécrit pas les blocs. Les fichiers existants conservent les tailles de blocs avec lesquelles ils ont été écrits. Il faut réécrire ou répliquer pour en bénéficier.
3) Is ZFS prefetch always good for sequential reads?
Généralement oui pour un flux séquentiel unique. Elle peut être moins efficace avec de nombreux lecteurs entrelacés. La désactiver globalement est rarement une bonne idée sauf preuve du contraire.
4) Does L2ARC increase streaming throughput?
Typiquement non pour les streams en une passe. L2ARC aide lorsque les données sont relues et que le working set ne tient pas en RAM. Pour le streaming, c’est souvent un surcoût avec peu de bénéfice.
5) Why is ARC miss% so high during streaming? Is that bad?
Un fort miss% est normal pour les workloads read-once. Ce qui compte, c’est si les disques/SSDs sont saturés et si les tailles de lecture sont assez grandes.
6) RAIDZ or mirrors for maximum sequential reads?
Les mirrors fournissent en général plus de parallélisme et des lectures plus prévisibles sous charge mixte. RAIDZ peut streamer correctement aussi, surtout avec plusieurs vdevs, mais un vdev RAIDZ large est un limiteur de débit.
7) Can compression improve sequential read throughput?
Oui. lz4 améliore souvent le débit en réduisant les octets lus sur disque. Sur NVMe rapides ou systèmes CPU-contraints, la compression peut devenir le goulot ; mesurez pour vos données.
8) How do I tell if I’m CPU-bound on ZFS reads?
Si les périphériques ne sont pas saturés, le débit plafonne et le CPU est occupé (souvent en kernel/system), vous êtes probablement lié au CPU pour la vérification de somme/decompression ou limité par des lecteurs mono-thread.
Confirmez avec des tests fio et des métriques CPU système.
9) My pool is 90% full. Can tuning save streaming performance?
Le tuning peut limiter les dégâts, mais il ne restaurera pas les lois de la physique. Une forte occupation augmente la difficulté d’allocation et la fragmentation. Agrandissez, ajoutez des vdevs ou migrez.
10) Why does scrub impact my streaming reads so much?
Le scrub est essentiellement une lecture structurée et implacable à travers tout le pool. Il concurrence directement vos lectures en streaming pour la même bande passante périphérique.
Étapes suivantes
Si vous voulez un débit de streaming maximal sur ZFS et vous voulez que ce soit fiable — pas seulement pour le jour du benchmark — faites ceci dans l’ordre :
- Mesurez le goulot :
zpool iostat -v,iostat -x, métriques CPU, et un testfiode lecture séquentielle directe. - Réglez les leviers importants : nombre/topologie de vdevs, recordsize du dataset pour les nouvelles données, taille de lecture/profondeur de file côté application.
- Protégez le reste du système : politiques de cache (
primarycache=metadata), planification des scrubs, et éviter les tunings globaux avec des impacts surprises. - Réécrivez si nécessaire : si les tailles de blocs et la fragmentation posent problème, la réplication vers un dataset neuf est souvent le « défrag » le plus propre.
Ensuite, écrivez ce que « bon » signifie pour votre pool : MB/s attendus par vdev, latence typique, et quelle activité d’arrière-plan est acceptable. Le vous du futur vous remerciera,
même si le vous du présent pense que la documentation est ce qui arrive aux autres.