Vous pouvez acheter des disques plus rapides, coller du NVMe sur la pile et continuer à regarder des graphiques de latence qui ressemblent à un sismographe.
Puis vous basculez deux propriétés ZFS—recordsize et compression—et soudain le même matériel donne l’impression d’avoir reçu une promotion.
Ou vous les configurez mal et vos CPU commencent une performance d’interprétation pendant que vos disques font la sieste. C’est le moment d’arrêter de deviner et de faire les calculs.
Ce que fait vraiment recordsize (et ce qu’il ne fait pas)
recordsize est la taille maximale d’un bloc de données que ZFS utilisera pour un fichier sur un dataset filesystem.
Ce n’est pas « la taille de bloc ». C’est un plafond, un indice et — selon votre charge — un volant de pilotage des performances.
Recordsize est un plafond, pas une obligation
Pour les fichiers ordinaires, ZFS utilise des enregistrements de taille variable jusqu’à recordsize. Un fichier avec des écritures de 4K ne devient pas magiquement des blocs de 128K
juste parce que le recordsize du dataset est 128K. ZFS stockera volontiers de petits blocs lorsque le pattern d’écriture l’exige.
Mais quand la charge produit des écritures séquentielles larges, recordsize devient votre réalité sur disque.
C’est pour cela que recordsize est le plus visible sur :
- lectures/écritures en flux importants (sauvegardes, stockages d’objets, médias, logs appendés en gros morceaux),
- datasets avec gros fichiers et bénéfices de read-ahead,
- charges où les pénalités de read-modify-write apparaissent (surcharges aléatoires dans de gros blocs).
Recordsize ne s’applique pas aux zvols de la même façon
Si vous servez des iSCSI/LUNs ou des disques VM via des zvols, le réglage est volblocksize, défini à la création du zvol.
C’est la taille de bloc fixe exposée au consommateur. Traitez-la comme un contrat d’API.
Le vilain caché : écritures partielles dans un bloc
Le mode douloureux pour « recordsize trop grand » n’est pas que ZFS ne peut pas faire de petits I/O ; c’est que les écrasements de petites parties à l’intérieur d’un grand enregistrement
peuvent déclencher des read-modify-write (RMW). ZFS doit lire l’ancien bloc, modifier une partie, et écrire un nouveau bloc complet (copy-on-write).
Cela coûte des I/O supplémentaires et augmente la latence — surtout quand le working set ne tient pas dans l’ARC et que vous effectuez des écritures synchrones.
Pensez à recordsize comme au choix de l’unité de « taille de transaction de stockage ». Des blocs plus grands réduisent la surcharge de métadonnées et peuvent augmenter le débit en streaming.
Des blocs plus grands augmentent aussi le rayon d’impact d’un petit overwrite.
Blague #1 : Mettre recordsize=1M pour une base de données à écritures aléatoires, c’est comme apporter un camion de déménagement pour livrer une clé de maison. Ça arrivera, mais personne n’est content.
La compression change l’économie
La compression ZFS n’est pas une fonctionnalité purement spatiale. C’est une fonctionnalité de performance parce qu’elle échange des cycles CPU contre une réduction des I/O physiques.
Cet échange peut être fantastique ou terrible selon la ressource qui vous bride.
L’effet central : octets logiques vs octets physiques
Chaque dataset ZFS a deux réalités :
- Logique : ce que l’application pense avoir écrit/lu.
- Physique : ce qui a réellement touché le disque après compression (et potentiellement après effets de padding, parité RAIDZ, etc.).
Quand la compression est efficace, vous réduisez les lectures/écritures physiques. Cela signifie :
- une consommation moindre de bande passante disque,
- potentiellement moins d’IOPS si une même requête logique correspond à moins de travail physique,
- un ARC plus efficace (parce que les blocs compressés en cache représentent plus de données logiques par octet de RAM).
LZ4 est souvent le défaut pour une raison
En production, compression=lz4 est le réglage « sûr et rapide » pour la plupart des données : configs, logs, charges textuelles, nombreuses bases, images VM.
Il est assez rapide pour que le CPU soit rarement le facteur limitant sauf si vous atteignez des débits très élevés ou des cœurs sous-dimensionnés.
Des compresseurs plus agressifs (niveaux zstd, par exemple) peuvent gagner beaucoup en espace et parfois en réduction d’I/O, mais le coût CPU devient réel.
Ce coût CPU se traduit par de la latence aux moments inopportuns : pics de compaction, fenêtres de sauvegarde, et ces « pourquoi l’API est lente seulement pendant la réplication ? ».
La compression interagit aussi avec recordsize
Le ratio de compression dépend de la taille des blocs. Des enregistrements plus grands compressent souvent mieux parce que le compresseur voit plus de redondance.
C’est pourquoi augmenter recordsize peut améliorer le ratio de compression sur des données de type log ou colonne.
Mais encore : si votre charge réécrit de petites parties de gros blocs, vous pouvez payer le RMW plus le coût de compression à chaque écriture renouvelée.
La mathématique du duo : IOPS, bande passante et CPU
recordsize et compression ne se contentent pas d’« optimiser ». Ils décident quelle ressource devient votre facteur limitant :
IOPS disque, bande passante disque ou CPU.
Commencez par les trois régimes de goulot
- Limité par les IOPS : latence dominée par le nombre d’opérations (I/O aléatoires, workloads riches en métadonnées, écritures synchrones).
- Limité par la bande passante : vous ne pouvez pas faire passer plus d’octets par le disque/réseau (streaming, scans, sauvegardes).
- Limité par le CPU : compression/décompression, checksums, chiffrement ou gros travaux ZFS consomment les cœurs.
Votre objectif de tuning n’est pas « performance maximale ». C’est « déplacer le goulot vers la ressource la moins chère ».
Le CPU est souvent moins coûteux que les IOPS sur du flash, et infiniment moins que les IOPS sur des disques rotatifs. Mais le CPU n’est pas gratuit quand les budgets de latence sont serrés.
Recordsize change la mathématique des IOPS
Supposons que vous ayez une charge lisant 1 GiB séquentiellement.
Si votre recordsize est 128K, cela fait environ 8192 blocs. Si c’est 1M, cela fait environ 1024 blocs.
Moins de blocs signifie moins de recherches de métadonnées, moins de validations de checksum, moins d’opérations I/O et un meilleur comportement de prélecture.
Pour les lectures en streaming, des blocs plus grands gagnent souvent.
Maintenant passez aux réécritures aléatoires de pages de 8K (bonjour les bases).
Si ces pages vivent à l’intérieur d’enregistrements de 128K, une mise à jour aléatoire de page peut se traduire par :
- lecture de l’ancien 128K (si pas dans l’ARC),
- modification de 8K à l’intérieur,
- écriture d’un nouveau 128K ailleurs (copy-on-write),
- mise à jour des métadonnées.
Ce n’est pas « une écriture de 8K ». C’est un motif I/O amplifié, plus de fragmentation au fil du temps.
Avec recordsize=16K (ou 8K selon la taille de page DB), vous réduisez l’amplification RMW.
Vous augmentez peut-être la surcharge des métadonnées, mais les bases vivent déjà dans ce monde.
La compression change la mathématique de la bande passante (et parfois des IOPS)
Si votre ratio de compression est 2:1, une « lecture de 100 MB » devient « 50 MB lus physiquement + décompression ».
Si vos disques étaient saturés, vous venez de libérer la moitié de la bande passante. La latence baisse, le débit augmente, tout le monde paraît ingénieux.
Si vos disques n’étaient pas saturés et que vos CPU étaient déjà occupés, vous venez d’acheter un nouveau problème.
La mathématique CPU : la décompression est sur le chemin de lecture
Les écritures paient le coût de compression. Les lectures paient le coût de décompression. Dans de nombreux systèmes, les lectures dominent la latence en queue.
Cela signifie que le comportement du décompresseur compte plus qu’on ne le croit.
La décompression LZ4 est typiquement rapide ; les compresseurs de niveau supérieur peuvent ne pas l’être.
ARC et compression : « plus de cache » sans acheter de RAM
ZFS stocke les blocs compressés dans l’ARC (les détails d’implémentation varient selon la version et les feature flags, mais l’effet pratique tient :
les données compressées rendent le cache plus efficace).
Une meilleure compression peut signifier plus de données logiques mises en cache par Go de RAM.
C’est une des raisons pour lesquelles compression=lz4 est un « oui » par défaut pour les datasets polyvalents.
Quand le duo est magique
Le meilleur scénario :
- recordsize suffisamment grand pour le pattern d’accès du workload,
- compression bon marché (lz4) et efficace (beaucoup de redondance),
- les disques sont la ressource coûteuse, les CPU ont de la marge.
Le résultat : moins d’octets physiques, moins d’attentes disque et des taux de hits en cache supérieurs.
Quand le duo est un piège
Le scénario piège :
- recordsize plus grand que la granularité des overwrites,
- le workload fait des mises à jour aléatoires,
- la compression ajoute un coût CPU à chaque réécriture d’un grand enregistrement,
- écritures synchrones + petit dispositif de log (ou pas de SLOG) amplifient la latence.
Le symptôme est souvent « le disque n’est pas occupé mais la latence est affreuse ». C’est de la contention CPU ou du chemin sync, pas la bande passante brute.
Playbook par workload : quoi régler selon quoi
Les valeurs par défaut existent parce qu’elles sont sûres, pas parce qu’elles sont optimales. Votre travail est d’avoir des opinions sûres.
Partages de fichiers généraux, répertoires personnels, configs
- recordsize : laissez la valeur par défaut (souvent 128K) sauf raison contraire.
- compression :
lz4. - Pourquoi : les charges mixtes bénéficient d’un recordsize moyen ; la compression réduit les I/O physiques pour les fichiers textuels.
Images VM sur datasets (qcow2/raw files)
- recordsize : couramment 16K ou 32K ; parfois 64K si les lectures sont majoritairement séquentielles.
- compression :
lz4(aide souvent plus qu’on ne l’imagine). - Pourquoi : l’I/O VM tend à être aléatoire et en petits blocs ; réduire l’amplification RMW.
zvols pour disques VM / iSCSI
- volblocksize : alignez sur l’attente du guest/filesystem (souvent 8K ou 16K ; parfois 4K).
- compression :
lz4sauf si le CPU est serré. - Pourquoi : volblocksize est fixe ; se tromper est une taxe permanente sauf migration.
PostgreSQL / MySQL / bases sur datasets filesystem
- recordsize : alignez sur la taille de page DB ou un multiple qui n’engendre pas de churn (souvent 8K ou 16K).
- compression :
lz4convient généralement ; testezzstduniquement si vous avez du CPU et cherchez de l’espace. - Pourquoi : les bases font de petites réécritures aléatoires ; de grands enregistrements induisent RMW et fragmentation.
Sauvegardes, archives, médias, blobs type objet
- recordsize : 512K ou 1M peut avoir du sens si lectures/écritures sont en streaming.
- compression :
zstd(niveau modéré) peut valoir le coup, oulz4pour un CPU prévisible. - Pourquoi : l’I/O séquentiel récompense les gros blocs ; le ratio de compression s’améliore avec de plus grandes fenêtres.
Logs (forte écriture en append)
- recordsize : la valeur par défaut suffit généralement ; si les logs sont volumineux et majoritairement lus séquentiellement ensuite, envisagez 256K.
- compression :
lz4presque toujours gagnant. - Pourquoi : les logs compressent extrêmement bien ; réduire les écritures physiques réduit aussi l’usure des SSD.
Workloads de petits fichiers (maildirs, arbres source, caches de paquets)
- recordsize : n’est pas le principal levier ; les petits fichiers utilisent déjà de petits blocs.
- compression :
lz4aide et peut accélérer les lectures en réduisant l’I/O disque. - Considérez : un vdev spécial pour les métadonnées/petits blocs si la latence vous préoccupe sérieusement.
Faits intéressants et contexte historique
- ZFS a été conçu pour l’intégrité des données de bout en bout : les checksums sur chaque bloc sont au cœur du système, pas une fonctionnalité additionnelle.
- Les premiers défauts ZFS visaient les gros disques et charges mixtes : recordsize 128K est devenu un compromis pragmatique pour le streaming et l’usage général.
- La compression dans ZFS a longtemps été « transparente » : les applications n’ont pas besoin de savoir ; le système de fichiers décide de la représentation sur disque.
- LZ4 est devenu le choix par défaut car il est bon marché : conçu pour la vitesse, il améliore souvent les performances en réduisant l’I/O sans faire exploser le CPU.
- Le copy-on-write modifie le coût des réécritures : ZFS n’écrase jamais en place ; voilà pourquoi les workloads à forte réécriture sont sensibles au dimensionnement des blocs.
- L’amplification d’écriture RAIDZ est réelle : de petites écritures aléatoires peuvent devenir de larges cycles read-modify-write au niveau de la stripe de parité, compliquant le choix de recordsize.
- L’ARC a popularisé « la RAM comme stockage » : ZFS met beaucoup en cache, et la compression augmente effectivement la capacité du cache pour les données compressibles.
- Les zvols ont été conçus pour les consommateurs bloc : mais leur volblocksize fixe rend les erreurs plus difficiles à corriger que pour recordsize sur les filesystems.
Trois micro-histoires d’entreprise tirées du terrain
Incident : la mauvaise hypothèse (« recordsize n’a pas d’importance pour les bases, non ? »)
Une entreprise de taille moyenne exécutait une plateforme d’analytics client sur ZFS. La base principale vivait sur un dataset cloné depuis une cible de sauvegarde.
Personne n’avait remarqué, car ça montait correctement, les performances semblaient « acceptables » et les graphiques étaient calmes — jusqu’à la fin du mois.
La fin de mois signifiait mises à jour massives, churn d’index et tâches de maintenance. La latence a grimpé puis explosé. Les threads applicatifs se sont accumulés.
L’équipe stockage a regardé l’utilisation disque : pas saturée. Les graphiques CPU sur les hôtes DB : pas saturés. Alors ils ont blâmé le réseau.
Ils ont réglé les buffers TCP comme si c’était 2009.
Le vrai problème était ennuyeux : le dataset avait recordsize=1M, hérité du profil de sauvegarde.
La base écrivait des pages de 8K. En période de churn, ZFS devait faire des read-modify-write sur de grands enregistrements et chasser les métadonnées.
Le pool n’était pas « occupé » en termes de bande passante ; il travaillait mal.
Ils ont corrigé en déplaçant la base vers un nouveau dataset avec recordsize=16K en gardant compression=lz4.
La migration a été la partie pénible. La récupération des performances a été immédiate, et les graphiques se sont calmés.
Leçon : « ça s’est monté, donc c’est bon » est la façon de se retrouver à déboguer la physique à 2 h du matin.
Optimisation qui s’est retournée contre eux : la phase d’enthousiasme zstd
Une autre organisation avait un problème de coût de stockage : des pools SSD rapides se remplissaient d’images VM et d’artefacts de build.
Quelqu’un a proposé une compression plus forte. Ils ont activé compression=zstd à un niveau agressif sur un dataset chaud.
Les économies d’espace étaient excellentes. Le ticket a été clos avec un soupir satisfait.
Deux semaines plus tard, leur CI a commencé à manquer ses SLA de build. Pas tout le temps — juste assez pour être rageant.
Le cluster n’était pas à court de CPU globalement, mais un sous-ensemble de nœuds montrait un iowait élevé et plus de CPU système aux heures de pointe.
L’array stockage n’était pas saturé. Le réseau allait bien. La tournée des blâmes a commencé : mises à jour du kernel, tuning du scheduler, « peut-être le DNS ».
Le véritable coupable : le CPU consacré à compresser et décompresser des artefacts chauds lors de charges bursty.
La forte compression avait amélioré la capacité mais augmenté la latence en queue et amplifié la contention sur les nœuds compute les plus chargés.
Le système ne tombait pas en panne ; il devenait simplement énervant et imprévisible — le pire type de régression en production.
Ils sont revenus à lz4 sur le dataset chaud et ont gardé zstd uniquement pour des archives froides en write-once.
Le bon résultat n’était pas « ne jamais utiliser zstd ». C’était « l’utiliser là où le pattern d’accès correspond au budget CPU ».
Pratique ennuyeuse mais correcte qui a sauvé la situation : datasets par workload
Une société financière avait une règle propre : chaque workload obtient son propre dataset, même si ça ressemble à de la paperasserie.
Bases, logs, images VM, sauvegardes — datasets séparés, propriétés explicites et un court README au point de montage.
Les nouveaux ingénieurs râlaient. Les seniors souriaient poliment et continuaient.
Un jour, une régression de performance est apparue après une mise à jour de plateforme. Les boot storms VM étaient plus lents, et un sous-ensemble d’invités avait une latence d’écriture élevée.
Parce que l’organisation avait des datasets séparés, ils ont pu comparer rapidement les propriétés et voir quels workloads étaient affectés.
Le dataset VM avait un recordsize ajusté pour cet environnement, et la compression était cohérente.
Le problème s’est avéré ailleurs (un souci sur le chemin d’écritures synchrones combiné à un dispositif SLOG défectueux),
mais l’isolation des datasets a évité une tentative de « tuning global » qui aurait cassé leurs bases.
Ils ont réparé le SLOG, et tout le reste est resté stable parce que rien d’autre n’avait été touché.
Leçon : la bonne pratique est souvent juste la séparation disciplinée. Ce n’est pas glamour. C’est comme éviter de saboter trois workloads en tuneant un seul.
Tâches pratiques : commandes, sorties, décisions (12+)
Ce sont des actions opérationnelles réelles. Chaque tâche inclut une commande, une sortie exemple, ce que cela signifie et la décision suivante.
Adaptez les noms de pool/dataset à votre environnement.
Tâche 1 : Lister les propriétés du dataset qui comptent (recordsize, compression)
cr0x@server:~$ zfs get -o name,property,value -s local,inherited recordsize,compression rpool/data
NAME PROPERTY VALUE
rpool/data recordsize 128K
rpool/data compression lz4
Signification : Vous voyez les réglages effectifs. S’ils sont hérités, remontez la chaîne pour savoir d’où ils viennent.
Décision : Si ce dataset héberge une DB ou des images VM, 128K peut être inadapté. Ne changez pas tout de suite — mesurez d’abord.
Tâche 2 : Vérifier si un dataset compresse réellement les données
cr0x@server:~$ zfs get -o name,property,value compressratio,logicalused,used rpool/data
NAME PROPERTY VALUE
rpool/data compressratio 1.85x
rpool/data logicalused 1.62T
rpool/data used 906G
Signification : La compression fonctionne. Logical est ce que les applis ont écrit ; used est l’espace physique consommé.
Décision : Si compressratio est proche de 1.00x sur des données chaudes, la compression peut être un coût CPU inutile. Envisagez de laisser lz4 quand même sauf si le CPU est serré.
Tâche 3 : Trouver rapidement les propriétés héritées (qui a défini ça ?)
cr0x@server:~$ zfs get -o name,property,value,source recordsize,compression -r rpool
NAME PROPERTY VALUE SOURCE
rpool recordsize 128K default
rpool compression off default
rpool/data recordsize 128K inherited from rpool
rpool/data compression lz4 local
rpool/data/db recordsize 1M local
rpool/data/db compression lz4 inherited from rpool/data
Signification : rpool/data/db a un recordsize local à 1M. C’est un signal d’alarme pour beaucoup de bases.
Décision : Confirmez le type de workload. Si c’est une DB avec pages 8K, planifiez une migration vers un dataset correctement dimensionné.
Tâche 4 : Surveiller les I/O en temps réel par dataset pour trouver le voisin bruyant
cr0x@server:~$ zpool iostat -v rpool 2
capacity operations bandwidth
pool alloc free read write read write
rpool 2.10T 1.40T 180 950 12.3M 88.1M
mirror 2.10T 1.40T 180 950 12.3M 88.1M
nvme0n1 - - 90 480 6.2M 44.0M
nvme1n1 - - 90 470 6.1M 44.1M
Signification : Beaucoup d’opérations d’écriture vs lectures modestes suggèrent une charge orientée écriture. Pas suffisant seul — corrélez avec la latence.
Décision : Si la bande passante est faible mais les ops élevées et la latence mauvaise, suspectez de petites écritures aléatoires et/ou des problèmes du chemin sync.
Tâche 5 : Vérifier l’état du pool et les erreurs avant de tuner
cr0x@server:~$ zpool status -v rpool
pool: rpool
state: ONLINE
status: Some supported features are not enabled on the pool.
action: Enable all features using 'zpool upgrade'. Once this is done,
the pool may no longer be accessible by software that does not support the features.
scan: scrub repaired 0B in 00:12:41 with 0 errors on Tue Dec 24 03:12:02 2025
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
mirror ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
errors: No known data errors
Signification : Pas d’erreurs, scrub propre. Bien — les problèmes de performance sont probablement liés à la configuration ou à la charge.
Décision : Poursuivez le diagnostic workload. Ne « tunez » pas un pool qui échoue silencieusement matériellement.
Tâche 6 : Mesurer le coût CPU de la compression via le temps système sous charge
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (server) 12/26/2025 _x86_64_ (16 CPU)
12:40:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:40:02 AM all 18.1 0.0 9.7 2.4 0.0 0.3 0.0 0.0 0.0 69.5
12:40:03 AM all 20.2 0.0 13.5 1.9 0.0 0.2 0.0 0.0 0.0 64.2
12:40:04 AM all 19.6 0.0 14.1 1.8 0.0 0.2 0.0 0.0 0.0 64.3
Signification : Un %sys élevé suggère du travail noyau (ZFS inclus). Un faible iowait suggère que les disques ne sont pas le goulot.
Décision : Si les performances sont mauvaises avec un iowait faible, investiguez les chemins CPU-bound (niveau de compression, checksumming, écritures synchrones, contention).
Tâche 7 : Observer l’efficacité de l’ARC et la pression mémoire
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:41:10 820 110 13 28 3 72 9 10 1 28.5G 31.8G
12:41:11 790 95 12 22 3 63 8 10 1 28.6G 31.8G
12:41:12 815 120 15 35 4 74 9 11 1 28.6G 31.8G
Signification : Le taux de miss n’est pas terrible. La taille ARC est proche de la cible. La compression peut permettre à l’ARC de « tenir plus de données logiques », mais les misses comptent toujours.
Décision : Si miss% est élevé sur une charge lecture-dominante, la compression peut aider (moins de lectures physiques), mais vous pourriez aussi avoir besoin de plus de RAM ou d’une meilleure localité.
Tâche 8 : Vérifier écritures logiques vs physiques par dataset (la compression réduit-elle la charge d’écriture ?)
cr0x@server:~$ zfs get -o name,property,value -r logicalused,used,compressratio rpool/data/vm
NAME PROPERTY VALUE
rpool/data/vm logicalused 800G
rpool/data/vm used 610G
rpool/data/vm compressratio 1.31x
Signification : Compression modérée. Les images VM compressent parfois un peu, parfois beaucoup selon l’OS et les blocs à zéro.
Décision : Gardez lz4. Si le CPU est élevé et que compressratio est proche de 1.00x, envisagez de le laisser de toute façon à moins de chasser la latence en queue.
Tâche 9 : Confirmer les tailles de blocs réellement écrites (pas seulement recordsize)
cr0x@server:~$ zdb -bbbbb rpool/data/db | head -n 12
Dataset rpool/data/db [ZPL], ID 236, cr_txg 41292, 1.12G, 2948 objects
Indirect blocks:
0 L0 16K 1.23G 11% 1.00x 79.3M
Signification : Cela montre la distribution réelle des blocs. Ici vous voyez des blocs L0 16K dominants, malgré un recordsize éventuellement plus grand.
Décision : Si vous attendiez des blocs 128K pour du streaming mais voyez beaucoup de 8K/16K, la charge n’est pas séquentielle (ou est fragmentée). Ajustez en conséquence.
Tâche 10 : Identifier si les écritures synchrones sont votre ennemi
cr0x@server:~$ zfs get -o name,property,value sync,logbias rpool/data/db
NAME PROPERTY VALUE
rpool/data/db sync standard
rpool/data/db logbias latency
Signification : Sync est standard (sûr). logbias latency privilégie l’usage du SLOG quand il est présent.
Décision : Si vous avez de nombreux fsync et pas de SLOG performant, la douleur de performance est attendue. Ne « corrigez » pas ça en mettant sync=disabled à moins d’aimer expliquer la perte de données.
Tâche 11 : Vérifier l’existence d’un vdev spécial (accélération métadonnées/petits blocs)
cr0x@server:~$ zpool status rpool | sed -n '1,40p'
pool: rpool
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
mirror ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
special
mirror ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
Signification : Il y a un special vdev mirror. Les métadonnées et éventuellement les petits blocs peuvent y atterrir.
Décision : Si la latence des petits fichiers et métadonnées est votre souci, un special vdev peut aider beaucoup. Mais c’est aussi un engagement de fiabilité — le perdre peut compromettre le pool.
Tâche 12 : Vérifier le réglage special_small_blocks (les petits blocs vont-ils vraiment sur special ?)
cr0x@server:~$ zfs get -o name,property,value special_small_blocks rpool/data
NAME PROPERTY VALUE
rpool/data special_small_blocks 0
Signification : Seules les métadonnées vont sur special, pas les petits blocs de données.
Décision : Si vous voulez que les petits blocs aillent sur special, réglez special_small_blocks=16K ou similaire — après réflexion sur la capacité et les domaines de panne.
Tâche 13 : Tester un changement de recordsize en toute sécurité sur un nouveau dataset
cr0x@server:~$ zfs create -o recordsize=16K -o compression=lz4 rpool/data/db16k
cr0x@server:~$ zfs get -o name,property,value recordsize,compression rpool/data/db16k
NAME PROPERTY VALUE
rpool/data/db16k recordsize 16K
rpool/data/db16k compression lz4
Signification : Vous avez créé un endroit pour migrer/tester sans muter le dataset existant en place.
Décision : Migrez un échantillon représentatif et faites des benchmarks. Évitez les « bascules héroïques en prod ».
Tâche 14 : Déplacer des données avec send/receive pour préserver les snapshots et réduire le downtime
cr0x@server:~$ zfs snapshot rpool/data/db@pre-migrate
cr0x@server:~$ zfs send -R rpool/data/db@pre-migrate | zfs receive -u rpool/data/db16k
cr0x@server:~$ zfs list -t snapshot -o name,used -r rpool/data/db16k | head
NAME USED
rpool/data/db16k@pre-migrate 0B
Signification : Le dataset et le snapshot existent sur la cible. Le -u le laisse démonté jusqu’à ce que vous soyez prêt.
Décision : Basculez en échangeant les points de montage ou en mettant à jour la config du service pendant une fenêtre de maintenance.
Tâche 15 : Valider que vous réduisez bien les I/O physiques après activation de la compression
cr0x@server:~$ zfs get -o name,property,value written,logicalused rpool/data/logs
NAME PROPERTY VALUE
rpool/data/logs written 145G
rpool/data/logs logicalused 312G
Signification : Logical used est beaucoup plus élevé que written physique, ce qui suggère que la compression réduit le trafic d’écriture.
Décision : Pour des logs append-heavy, gardez la compression. Elle réduit l’usure disque et améliore souvent la vitesse de lecture pendant les investigations.
Guide de diagnostic rapide
C’est le workflow « quelqu’un hurle dans Slack ». L’objectif est d’identifier si vous êtes limité par IOPS, bande passante, CPU ou par le chemin sync — rapidement.
Première étape : confirmez que ce n’est pas un pool défaillant ou un scrub/resilver en cours
- Exécutez
zpool status. Si vous voyez des erreurs, des vdevs dégradés ou un resilver en cours, arrêtez le tuning et commencez à réparer le matériel ou terminer la récupération. - Vérifiez si un scrub est en cours. Les scrubs peuvent être polis ou agressifs selon les tunables et la charge.
Deuxième étape : décidez si le goulot est disque ou CPU
- Signes limités par le disque : iowait élevé, utilisation élevée du device, bande passante proche des limites device, latence qui augmente avec le débit.
- Signes limités par le CPU : iowait bas mais CPU système élevé, débit plafonné tôt, pics de latence sans saturation disque.
Troisième étape : tester si les écritures synchrones sont le véritable coupable
- Vérifiez la propriété
syncdu dataset et si la charge utilise fsync/O_DSYNC. - Si vous avez un SLOG, validez qu’il est sain et rapide. Si vous n’en avez pas, acceptez que les workloads sync-heavy seront limités par la latence du vdev principal.
Quatrième étape : comparer recordsize/volblocksize au pattern I/O
- Pour DB/écritures aléatoires, un recordsize trop grand peut causer une amplification RMW.
- Pour les workloads en streaming, un recordsize trop petit gaspille des IOPS et du CPU sur les métadonnées/checksums.
Cinquième étape : vérifier que la compression aide vraiment et n’est pas juste « activée »
- Regardez
compressratioet logical vs physical usage. - Si le ratio est mauvais et le CPU élevé, envisagez lz4 au lieu d’algorithmes plus lourds, ou désactivez la compression pour les données déjà compressées.
Erreurs courantes : symptôme → cause → correction
1) « Les disques sont au repos mais la latence est élevée »
- Symptôme : faible bande passante, iowait bas, mais pics de latence applicative.
- Cause : chemin CPU-bound (niveau de compression trop élevé, coût checksum/chiffrement) ou contention sur les écritures synchrones.
- Correction : rétrograder la compression à
lz4, assurer de la marge CPU, valider le SLOG pour les workloads sync et éviter les enregistrements surdimensionnés pour les patterns d’overwrite.
2) « Les écritures DB ont ralenti après avoir augmenté recordsize pour le débit »
- Symptôme : latence d’écriture plus élevée, pics imprévisibles pendant maintenance/vacuum/compaction.
- Cause : amplification RMW due aux réécritures de petites pages dans de grands enregistrements ; la fragmentation s’aggrave avec le temps.
- Correction : migrer vers un dataset avec recordsize aligné sur la taille de page DB (souvent 8K/16K). Garder compression lz4 sauf si le CPU est contraint.
3) « Compression activée, mais le pool continue de se remplir et les perfs n’ont pas changé »
- Symptôme :
compressratio~1.00x, pas de réduction significative des écritures physiques. - Cause : les données sont déjà compressées/chiffrées (médias, zip, nombreuses images VM avec FS chiffré).
- Correction : laissez lz4 si le CPU est bon et que vous voulez des gains occasionnels ; sinon désactivez la compression pour ce dataset et cessez de payer le coût CPU inutile.
4) « Les lectures séquentielles sont plus lentes que prévu sur des disques rapides »
- Symptôme : débit en dessous des capacités hardware pendant scans/sauvegardes.
- Cause : recordsize trop petit, générant trop d’IOPS et de surcharge ; ou données fragmentées en petits blocs à cause d’un historique d’écriture.
- Correction : utiliser un dataset à gros record pour les données streaming (256K–1M). Pour des données existantes, envisagez de réécrire (send/recv vers un nouveau dataset) pour reblocker.
5) « Activer une forte compression a sauvé de l’espace mais cassé les SLA »
- Symptôme : gains d’espace, mais latence en pointe et régressions pendant les pics.
- Cause : contention CPU due à la compression/décompression lourde sur le chemin chaud.
- Correction : utiliser lz4 pour les données chaudes ; réserver zstd aux datasets froids et non sensibles à la latence ; benchmarkez avec la concurrence réelle.
6) « On a changé recordsize et rien n’a changé »
- Symptôme : aucune différence observable après avoir réglé recordsize.
- Cause : recordsize affecte les nouvelles écritures. Les blocs existants conservent leur ancienne taille jusqu’à réécriture.
- Correction : réécrire les données via réplication/migration (send/recv) ou réécriture côté application ; valider avec
zdbla distribution des blocs.
Blague #2 : Si vous changez recordsize d’un dataset et vous attendez que les anciens blocs se remodelent, félicitations — vous avez inventé le yoga du stockage.
Listes de contrôle / plan étape par étape
Étapes : choisir recordsize + compression en toute sécurité
- Classifiez la charge : overwrite aléatoire (DB), lecture aléatoire (VM), séquentielle (backup/media), mixte (home dirs).
- Trouvez l’unité I/O : taille de page DB, taille de bloc VM, taille d’objet typique, taille de chunk des logs.
- Choisissez un recordsize de départ :
- DB : 8K–16K (aligner sur les pages).
- Fichiers VM : 16K–64K.
- Streaming : 256K–1M.
- Mixte : 128K.
- Activez
compression=lz4sauf raison CPU/tail-latency contraire. - Créez un nouveau dataset avec ces propriétés ; ne muter pas l’ancien si possible.
- Migrez un échantillon représentatif et faites des benchmarks avec une concurrence proche de la production.
- Validez les résultats :
- Le
compressratios’est amélioré ? - Les percentiles de latence se sont améliorés ?
- La marge CPU reste saine ?
- Le
- Déployez progressivement : migrez service par service, pas « tout le pool à la fois ».
Checklist : avant de toucher aux réglages en production
- Pool sain (
zpool status). - Scrub récent terminé sans erreurs.
- Vous savez si la charge est sync-heavy.
- Vous pouvez revenir en arrière (snapshots + plan de migration testé).
- Vous avez des métriques de base (percentiles de latence, CPU, IOPS, bande passante).
- Vous ne mélangez pas des workloads sans rapport dans un même dataset avec des propriétés inadaptées à tous.
Checklist : politique de compression par type de données
- Texte/logs/configs : lz4 activé.
- Bases de données : lz4 activé (généralement), recordsize aligné.
- Médias (déjà compressés) : optionnel ; souvent désactivé sauf gains mesurés.
- Données chiffrées au repos dans des fichiers : la compression n’aidera pas ; n’attendez pas de miracles.
- Archives froides : envisagez zstd si le budget CPU est séparé du budget latence.
Une idée de fiabilité (paraphrasée) à garder
Idée paraphrasée : planifiez les pannes, car tout échoue un jour — concevez pour que les pannes soient survivables.
— Werner Vogels
FAQ
1) Dois-je toujours activer compression=lz4 ?
Pour la plupart des datasets, oui. Cela réduit souvent l’I/O physique et améliore le cache effectif sans coût CPU notable.
Exceptions : données déjà compressées/chiffrées sur des systèmes CPU-limitées avec des contraintes strictes de latence.
2) Si je change recordsize, est-ce que ça réécrit les blocs existants ?
Non. Recordsize s’applique aux nouvelles écritures. Les blocs existants gardent leur taille jusqu’à réécriture.
Pour « reblocker », migrez généralement les données vers un nouveau dataset (send/recv) ou réécrivez les fichiers côté application.
3) Quel recordsize pour PostgreSQL ?
Points de départ courants : 8K ou 16K (les pages PostgreSQL sont typiquement 8K). 16K peut convenir si vous observez un certain comportement séquentiel.
La bonne réponse : alignez sur le comportement des pages et benchmarkez votre workload, surtout pour les tables à forte mise à jour.
4) Qu’en est-il de MySQL/InnoDB ?
InnoDB utilise souvent 16K de page par défaut. Un recordsize 16K est un point de départ raisonnable pour des datasets à forte écriture.
Si vous faites de larges scans séquentiels et majoritairement des appends, vous pouvez supporter plus grand. Mesurez avant d’être créatif.
5) Pourquoi un grand recordsize nuit aux écritures aléatoires si ZFS peut stocker de petits blocs ?
Le problème n’est pas les petites écritures initiales — c’est les overwrites partiels et le comportement copy-on-write qui créent des cycles read-modify-write et de la fragmentation.
De grands enregistrements augmentent la quantité de données réécrites pour un petit changement.
6) Est-ce que zstd vaut le coup ?
Parfois. Il peut fournir une meilleure compression que lz4, surtout sur des données froides ou write-once.
Sur des datasets chauds et sensibles à la latence, il peut se retourner contre vous en augmentant la contention CPU et la latence en queue.
7) La compression aide les IOPS, ou seulement la bande passante ?
Elle réduit principalement la bande passante (octets). Mais réduire les octets peut indirectement réduire la pression IOPS si les opérations se terminent plus vite,
et améliore la densité du cache, ce qui peut réduire les lectures physiques (et donc les IOPS) quand les taux de hit ARC augmentent.
8) Recordsize vs volblocksize : lequel régler pour le stockage VM ?
Si vous stockez des disques VM comme fichiers sur un dataset, réglez recordsize. Si vous utilisez des zvols, réglez volblocksize à la création.
Ne les confondez pas ; la volblocksize d’un zvol est plus difficile à changer par la suite.
9) Puis-je définir différentes valeurs recordsize dans un même dataset ?
Pas par répertoire via les propriétés ZFS standards. C’est par dataset. Le modèle pratique : créer plusieurs datasets avec des propriétés différentes
et les monter là où l’application attend des comportements I/O distincts.
10) Comment savoir si je suis CPU-bound à cause de la compression ?
Typiquement vous verrez un iowait bas, un CPU système élevé, et un débit qui plafonne avant que les disques ne soient saturés.
Confirmez en comparant les performances avec lz4 vs compression plus lourde sur un dataset test, en reproduisant la concurrence production.
Conclusion : prochaines étapes à faire aujourd’hui
- Inventoriez vos datasets : lister
recordsize,compressionet les sources d’héritage. Trouvez le cas « profil de sauvegarde qui exécute la production ». - Choisissez un workload qui est soit sensible à la latence soit coûteux (base, stockage VM, cache de build). Donnez-lui un dataset dédié.
- Mettez des valeurs par défaut sensées :
- Données générales chaudes :
compression=lz4,recordsize=128K. - DB :
compression=lz4,recordsize=8Kou16K. - Backups streaming :
recordsize=512Kou1M, compression selon le budget CPU.
- Données générales chaudes :
- Migrez, ne muter pas : créez un nouveau dataset avec les bons réglages et déplacez les données via send/recv. C’est la manière d’éviter des régressions surprises.
- Remesurez : logical vs physical, percentiles de latence, marge CPU, et la question « les disques sont-ils réellement occupés ? ».
Recordsize et compression ne sont pas des « astuces de tuning ». Ce sont des décisions d’architecture exprimées par deux propriétés.
Faites-les délibérément, par workload, et votre budget matériel ira plus loin — sans transformer vos CPU en stagiaires non payés.