ZFS a un petit curseur nommé sync qui semble inoffensif jusqu’à ce qu’il vous ruine la semaine — ou qu’il vous la sauve. Le tourner dans un sens calme votre courbe de latence, vos benchmarks ont l’air héroïques et votre hôte VM « semble rapide ». Le tourner dans l’autre sens vous donne les garanties qu’aiment les auditeurs et qui permettent aux opérateurs de dormir. Le piège est que les deux résultats peuvent être vrais en même temps, selon ce que vous entendez par « écrit sur disque ».
Ce n’est pas une leçon de morale sur « ne jamais désactiver la sécurité ». C’est un guide de terrain pour les personnes qui gèrent de la production : ce que fait réellement sync, pourquoi il peut étrangler un système, comment les dispositifs SLOG aident (et où ils ne le font pas), et comment choisir des réglages cohérents avec les promesses de votre charge de travail. L’objectif est simple : être rapide sans transformer accidentellement votre stockage en suggestion polie.
Ce que « sync » de ZFS signifie vraiment (et ce qu’il ne signifie pas)
Dans ZFS, la propriété de dataset sync contrôle la manière dont ZFS traite les requêtes d’écriture synchrones. Cette formulation est importante. ZFS ne décide pas de manière aléatoire d’être synchrone ; c’est l’appelant qui le demande.
Une écriture synchrone est celle où l’application (ou le protocole) dit : « Ne signalez pas le succès tant que ces données ne sont pas sur un stockage stable. » Le stockage stable est un stockage qui survivra à un crash et à une coupure de courant soudaine. Pas « c’est en RAM », pas « le contrôleur dit que c’est en cache », pas « le cache de pages Linux a l’air optimiste aujourd’hui ». Stable.
ZFS met en œuvre cette garantie en consignant l’intention d’écriture dans le ZIL (ZFS Intent Log). Si vous avez un dispositif de log séparé (un SLOG), ZFS peut placer ces données ZIL sur un périphérique à faible latence pour accélérer les écritures synchrones. Plus tard, ZFS intègre ces changements dans le pool principal lors des commits des groupes de transactions (TXG).
Deux implications immédiates :
syncne rend pas votre système « sûr » à lui seul. Il définit ce que ZFS fera lorsque l’appelant demande des sémantiques de synchronisation. Si l’appelant ne le demande jamais (ou est mal configuré), vous pouvez toujours perdre des données lors d’une panne de courant.syncpeut absolument vous rendre plus rapide. Mais l’accélération provient souvent de la suppression des garanties de durabilité. C’est pourquoi ce réglage est célèbre : c’est l’un des rares boutons où performances et sécurité sont directement liées.
Voici la première plaisanterie, car elle nous servira plus tard : désactiver sync revient à retirer votre détecteur de fumée parce qu’il sonne quand vous faites griller du pain — paisible jusqu’à ce que ça ne le soit plus.
Contexte historique et faits intéressants
Un peu de contexte permet de rendre le comportement moins magique et plus technique :
- ZFS est né chez Sun Microsystems au début des années 2000, conçu pour l’intégrité de bout en bout et des flux d’administration sensés à grande échelle — à une époque où « utiliser RAID et espérer » était encore un plan courant.
- Le ZIL n’est pas un cache d’écriture pour tout. Il existe spécifiquement pour satisfaire les sémantiques synchrones ; la plupart des écritures asynchrones ne le touchent jamais.
- Un SLOG n’est pas un « cache SSD ». C’est un périphérique dédié pour stocker rapidement le ZIL. Il n’accélère pas les lectures et n’accélère pas automatiquement toutes les écritures.
- Beaucoup de baies de stockage d’entreprise vendaient une « write cache NVRAM » comme ingrédient magique rendant les écritures synchrones rapides. En ZFS, un SLOG protégé contre la perte de courant joue un rôle similaire, mais seulement pour le ZIL.
- NFS a la réputation d’être « mystérieusement lent » en grande partie parce qu’il a tendance à demander des sémantiques synchrones pour de nombreuses opérations. Si le stockage ne peut pas committer rapidement, le protocole réseau semble coupable.
- Les bases de données utilisent souvent
fsync()comme ligne de démarcation. PostgreSQL, MySQL/InnoDB et d’autres se reposent sur des appels de vidage explicites pour maintenir la durabilité des transactions. - Les piles de virtualisation amplifient la douleur. Une VM effectuant des écritures synchrones devient un hôte effectuant des écritures synchrones, multiplié par chaque invité. Un locataire bruyant axé sur la durabilité peut dominer la latence.
- Les bugs d’« ordonnancement d’écritures » étaient courants dans les systèmes de fichiers et les contrôleurs. Le design de ZFS (copy-on-write + checksums) n’élimine pas le besoin de sync, mais rend la corruption plus facile à détecter et plus difficile à créer silencieusement.
Les trois modes : standard, always, disabled
La propriété sync est par dataset (système de fichiers ou zvol). Elle a trois valeurs pertinentes :
1) sync=standard (par défaut)
Cela signifie : respecter la demande de l’appelant. Si l’application émet des écritures synchrones ou appelle fsync()/fdatasync(), ZFS consigne l’intention dans le ZIL et ne signale le succès qu’ensuite.
Opérationnellement : c’est le mode « faire ce que l’application a demandé ». Si la performance est mauvaise ici, c’est un signal réel : votre charge de travail demande la durabilité et votre chemin de stockage ne peut pas la fournir rapidement.
2) sync=always
Cela force toutes les écritures à être traitées comme synchrones, même si l’appelant ne l’a pas demandé.
Quand l’utiliser : lorsque vous ne faites pas confiance à la charge de travail ou au middleware pour demander correctement la synchronisation, mais que vous avez quand même besoin d’un comportement durable. Parfois utilisé pour des exports NFS dont les charges mentent souvent sur leurs besoins de durabilité, ou sur certaines images VM où vous voulez garantir la sécurité au niveau de l’hôte indépendamment des réglages invités.
Compromis : si vous n’avez pas un SLOG rapide et sûr, vous pouvez transformer un pool décent en musée de la latence.
3) sync=disabled
Cela indique à ZFS de traiter les requêtes synchrones comme asynchrones. Il accusera réception des écritures synchrones avant qu’elles ne soient réellement sur un stockage stable.
Quand l’utiliser : pour des données que vous pouvez vous permettre de perdre en cas de crash (espace de travail, caches, intermédiaires d’analytique transitoires), ou dans des architectures très spécifiques où la durabilité est gérée ailleurs (par exemple, l’application a son propre journal de commit répliqué et vous acceptez expressément la perte locale).
Risque : toute application qui croit avoir obtenu un commit durable peut se tromper. Cela inclut les bases de données. Cela inclut les systèmes de fichiers VM. Cela inclut les clients NFS effectuant des écritures sûres.
Deuxième plaisanterie, puis on redevient sérieux : définir sync=disabled sur un volume de base de données revient à mettre « probablement » au milieu de votre grand livre financier — les auditeurs n’apprécient pas.
Qui demande des écritures synchrones : apps, bases de données, NFS, hyperviseurs
La plupart des drames de performance autour de sync proviennent d’une mauvaise compréhension de qui demande la synchronisation et pourquoi.
Bases de données
Les bases de données convertissent souvent « transaction validée » en un fsync() sur un journal de reprise (WAL) ou redo log. Le journal est plutôt séquentiel, mais l’exigence est stricte : quand la base de données signale commit, le journal doit survivre à un crash. Si ZFS met 5 ms pour satisfaire cela, la latence du commit de la base est d’au moins 5 ms, même si tout le reste est rapide.
Certaines bases peuvent relaxer cela (par ex. modes « async commit »), mais c’est une décision au niveau applicatif. Le stockage ne devrait pas changer silencieusement le sens de « commit » sans que vous le sachiez.
NFS
Les clients NFS demandent souvent des écritures stables, et les serveurs doivent les honorer. Sur des serveurs NFS sur ZFS, cela signifie que le chemin ZIL/SLOG devient le point chaud. Vous pouvez avoir un pool ultra-rapide pour le débit asynchrone et néanmoins subir une latence NFS terrible si les commits synchrones sont lents.
Virtualisation (zvols, images VM)
Les hyperviseurs et les systèmes de fichiers invités peuvent générer un nombre surprenant d’opérations synchrones — mises à jour de métadonnées, commits de journaux, barrières, flushs. Un seul réglage « sûr » dans un invité peut se traduire par des flushs constants sur l’hôte, et ces flushs se répercutent directement sur le chemin ZIL.
C’est pourquoi vous verrez la plainte classique : « Mon pool SSD est rapide mais mon hôte VM est lent. » Souvent le pool est bon pour les écritures en masse, mais la latence des écritures synchrones est médiocre.
Le chemin d’écriture synchrone : TXGs, ZIL, SLOG, et ce qui atteint réellement le stockage stable
ZFS écrit les données en groupes de transactions (TXG). Les changements sont accumulés en mémoire et périodiquement commités sur disque par lots. Ce regroupement rend ZFS efficace : il transforme beaucoup de petites écritures aléatoires en IO plus ordonné.
Les requêtes synchrones compliquent cela. L’application ne peut pas attendre le prochain commit TXG (qui peut être à plusieurs secondes). Donc ZFS utilise le ZIL : un journal d’intention qui enregistre suffisamment d’informations pour rejouer l’opération après un crash. Le ZIL est écrit rapidement, puis l’écriture synchrone peut être accusée. Plus tard, quand le TXG commit, les données réelles arrivent dans leurs structures finales sur disque et les entrées ZIL deviennent obsolètes.
Vérité opérationnelle clé : le ZIL n’est lu qu’au cours de la récupération après crash. En fonctionnement normal, il est écrit, pas lu. Un dispositif SLOG n’est pas là pour améliorer les lectures en état stable ; il est là pour accepter rapidement et en toute sécurité de petites écritures sensibles à la latence.
Autre vérité : si vous n’avez pas de SLOG séparé, les blocs ZIL vivent sur le pool principal. Cela peut aller sur des pools très rapides et à faible latence — en particulier les tout-flash avec protection contre la perte de courant. Sur des pools plus lents (disques spinning, ou SSDs avec mauvaise latence sous écritures synchrones), cela peut être brutal.
Réalités du SLOG : ce qu’il accélère, ce qu’il ne peut pas
On achète un SLOG pour la même raison qu’on achète du meilleur café : on veut que les matins fassent moins mal. Mais un SLOG n’est pas un dispositif miracle. Il accélère une chose : la latence des accusés réception des écritures synchrones.
Ce que le SLOG aide
- Charges NFS très synchrones qui sont limitées par la latence de commit.
- Bases de données liées à la latence de commit (et où la base insiste pour des commits durables).
- Clusters VM où les flushs sont fréquents et bloquants.
Ce que le SLOG n’aide pas
- La latence de lecture ou les IOPS de lecture (c’est le domaine de l’ARC/L2ARC, et même là il y a des nuances).
- Le débit d’écriture asynchrone en masse (c’est principalement les vdevs principaux et le comportement des TXG).
- Les charges qui émettent peu d’écritures synchrones ; vous ne le ressentirez pas.
Ce qui fait un bon SLOG
Deux propriétés : faible latence sous écritures synchrones et protection contre la perte de courant. Vous voulez que le périphérique accuse réception des écritures uniquement lorsque les données sont réellement en sécurité. Les SSD grand public peuvent être rapides mais mentir sur la durabilité des flushs. Les SSD d’entreprise (ou les périphériques conçus pour le journal d’écriture) font généralement mieux car ils ont des condensateurs et un firmware adaptés à cette tâche.
La taille n’est pas le critère principal. Le SLOG n’a besoin de contenir qu’une courte fenêtre de transactions synchrones en attente — typiquement quelques secondes, pas tout le dataset. C’est la latence, pas la capacité, que vous achetez.
Miroir du SLOG
Si un périphérique SLOG tombe en panne, le pool peut continuer (ZFS peut basculer), mais vous risquez de perdre les dernières transactions synchrones qui avaient été accusées si le dispositif de log meurt de façon inappropriée. En pratique, de nombreuses équipes miroirent le SLOG pour une paranoïa qui est souvent justifiée — en particulier sur du stockage partagé pour VMs ou bases de données.
Trois mini-récits du monde corporate (histoires de guerre réalistes)
Mini-récit n°1 : Un incident causé par une mauvaise hypothèse
L’équipe stockage a hérité d’un cluster NFS sur ZFS servant une ferme de builds et quelques services internes « petits ». Un nouveau service est arrivé : un système de mise en file d’état qui écrivait de petits messages en continu et se reposait sur des commits synchrones pour être correct. Tout le monde a supposé que ce serait « comme les autres apps », parce qu’il vivait dans le même cluster Kubernetes et utilisait la même classe NFS.
Ce ne l’était pas. Le service de file forçait des écritures stables, et la latence est passée de « correcte » à « que se passe-t-il » du jour au lendemain. Les jobs de build ont commencé à expirer à des endroits incompréhensibles. L’équipe réseau a été appelée parce que les graphes de latence NFS ressemblaient à de la perte de paquets. L’SRE de garde a redémarré des daemons, puis des nœuds, puis a remis en question la réalité.
Après quelques heures de jeu du chat et de la souris, quelqu’un a lancé zpool iostat -v 1 et a remarqué un petit périphérique (le seul SLOG) saturé par de nombreuses écritures avec une latence affreuse, tandis que le pool principal avait de la marge. Le SLOG était un ancien SSD SATA grand public — rapide en benchs, terrible sur les écritures synchrones soutenues, et vraisemblablement peu fiable sur les flushs. Il était devenu le goulot et la source de la latence extrême.
La correction a été banale : remplacer le SLOG par un périphérique basse-latence protégé contre la perte de courant et le miroiter. Les performances se sont stabilisées immédiatement. Le postmortem n’était pas une histoire de blâme ; c’était une histoire d’hypothèses. L’environnement était passé de « artefacts de build majoritairement asynchrones » à « charge nécessitant des syncs lourds », et les réglages de stockage n’avaient pas suivi.
Mini-récit n°2 : Une optimisation qui s’est retournée contre eux
Une équipe de plateforme virtualization avait un pool ZFS hébergeant des disques VM (zvols). Un nouveau cluster est entré en production et, sous charge, il était moins performant que l’ancien — bien que le matériel soit plus récent. Quelqu’un a trouvé un billet de blog suggérant sync=disabled pour « gains massifs de performance » sur le stockage VM. Ils l’ont testé sur un hôte de staging avec de l’IO synthétique et obtenu des chiffres magnifiques.
Alors ils l’ont déployé progressivement. Le gain de performance était réel : la latence de commit s’est effondrée, le wait IO a chuté, les locataires ont arrêté de se plaindre. On se sentait comme des héros — jusqu’au premier événement de coupure réelle. Pas une panne de datacenter catastrophique, juste un disjoncteur pendant une maintenance qui a coupé un rack. Les hôtes ont redémarré, le stockage s’est importé proprement, et la plupart des VMs sont revenues en ligne correctement.
Mais quelques-unes ne l’ont pas fait. Des systèmes de fichiers étaient corrompus d’une manière que le journal ne corrigeait pas. Une VM base de données est revenue mais il manquait les dernières minutes de transactions « commises » — des transactions que l’application avait accusées auprès de services en amont. Le réglage « rapide » avait changé silencieusement le sens de « commit » à l’intérieur de ces invités. Cela a causé une corruption logique : pas des blocs brisés, mais des vérités métier brisées.
Le retour arrière a été simple. Le nettoyage ne l’a pas été. Ils ont dû reconstituer des commandes manquantes et retraiter des événements à partir des journaux en amont. Dans le rapport final, la leçon n’était pas « ne jamais tuner ZFS ». C’était : si vous désactivez sync sur le stockage VM, vous prenez une promesse de durabilité au nom de chaque invité, et vous feriez mieux d’avoir une architecture qui la tolère. Sinon votre benchmark n’est qu’une supercherie.
Mini-récit n°3 : Une pratique ennuyeuse mais correcte qui a sauvé la mise
Une équipe de services financiers exploitait une paire de serveurs ZFS exportant NFS vers un cluster applicatif. Ils avaient l’habitude, jugée fastidieuse, de lancer avant chaque pic trimestriel un « drill de durabilité ». C’était simple : vérifier les propriétés sync des datasets, vérifier la santé du SLOG, vérifier que les flushs se comportaient comme attendu, et exécuter une simulation contrôlée de perte de courant en laboratoire sur du matériel de la même classe.
Les ingénieurs se plaignaient que c’était du culte cargo. Rien ne tombait jamais pendant le test. C’était le but. C’était l’équivalent stockage de vérifier votre parachute au sol.
Puis ils ont eu un incident réel : un bug de firmware a fait qu’un des périphériques de log commençait à reporter un état sain tout en se mettant en timeout silencieusement sous certaines charges de queue. ZFS ne l’a pas immédiatement détecté comme défaillant, mais la latence a explosé chaque fois que la charge devenait sync-heavy. Parce que l’équipe disposait de chiffres de latence de référence issus des drills précédents, ils ont détecté la déviation rapidement et n’ont pas perdu une nuit à blâmer NFS, le réseau ou l’application.
Ils ont remplacé la paire de SLOG pendant une fenêtre de maintenance, et le cluster est revenu à la normale. Pas de perte de données, pas de mystère. C’était de l’ingénierie ennuyeuse, ce que vous voulez quand de l’argent est en jeu.
Tâches pratiques : commandes, quoi surveiller et comment interpréter
Les commandes ci-dessous supposent un environnement OpenZFS typique sur Linux. Adaptez les noms de pools/datasets à votre système. Chaque tâche inclut ce que la sortie signifie en pratique.
Task 1: Find your dataset sync settings (and inheritance)
cr0x@server:~$ zfs get -r -o name,property,value,source sync tank
NAME PROPERTY VALUE SOURCE
tank sync standard default
tank/vm sync disabled local
tank/vm/critical sync standard inherited from tank
tank/nfs sync standard local
Interprétation : Ne regardez pas seulement la racine du pool. Un seul dataset « utile » avec sync=disabled peut se cacher sous votre hiérarchie de stockage VM. La colonne source est votre détecteur de vérité : local vs inherited vs default.
Task 2: Check whether you even have a SLOG (and what it is)
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 00:18:42 with 0 errors on Mon Dec 16 03:10:05 2025
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
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
errors: No known data errors
Interprétation : La section logs est votre SLOG. Si elle manque, votre ZIL vit sur les vdevs principaux. Si c’est un seul périphérique (non miroiré), décidez si le profil de risque est acceptable.
Task 3: Watch per-vdev latency under load
cr0x@server:~$ zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 1.20T 2.40T 110 980 8.5M 72.1M
mirror-0 1.20T 2.40T 110 220 8.5M 15.4M
nvme0n1 - - 60 120 4.2M 7.8M
nvme1n1 - - 50 100 4.3M 7.6M
logs - - - -
mirror-1 - - 0 760 0K 56.7M
nvme2n1 - - 0 380 0K 28.4M
nvme3n1 - - 0 380 0K 28.3M
-------------------------- ----- ----- ----- ----- ----- -----
Interprétation : Si les périphériques de log supportent la majorité des écritures pendant que les vdevs principaux sont calmes, votre charge est sync-heavy. Si les performances sont mauvaises, le SLOG est le premier suspect.
Task 4: Confirm ZFS sees the right ashift (sector size alignment)
cr0x@server:~$ zdb -C tank | grep -E "ashift|vdev_tree" -n | head
52: vdev_tree:
83: ashift: 12
121: ashift: 12
Interprétation : ashift=12 signifie secteurs 4K. Un mauvais alignement (ashift trop petit) peut créer une amplification d’écriture et une latence désagréable, y compris pour le trafic sync.
Task 5: Check ZFS pool health and error counters
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 00:18:42 with 0 errors on Mon Dec 16 03:10:05 2025
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
Interprétation : Déboguer la performance sync sur un pool avec des erreurs latentes, c’est comme régler un moteur avec une pompe à huile cassée. Réparez d’abord l’intégrité.
Task 6: Identify sync-heavy callers by watching fsync activity (Linux)
cr0x@server:~$ sudo perf trace -e fsync,fdatasync,openat -a --duration 10
0.000 ( 0.008 ms): postgres/1931 fdatasync(fd: 7) = 0
0.012 ( 0.006 ms): postgres/1931 fdatasync(fd: 7) = 0
0.030 ( 0.010 ms): qemu-kvm/2210 fsync(fd: 31) = 0
0.044 ( 0.009 ms): qemu-kvm/2210 fsync(fd: 31) = 0
Interprétation : Vous recherchez la fréquence. Si vous voyez des milliers d’appels sync par seconde, votre budget de latence est dépensé sur la durabilité.
Task 7: Measure sync write latency with fio (direct, sync-like)
cr0x@server:~$ fio --name=syncwrite --filename=/tank/test/syncwrite.bin \
--rw=write --bs=4k --iodepth=1 --numjobs=1 --direct=1 \
--fsync=1 --size=1G --runtime=30 --time_based=1
syncwrite: (g=0): rw=write, bs=4K-4K, ioengine=psync, iodepth=1
...
write: IOPS=6200, BW=24.2MiB/s (25.4MB/s)(726MiB/30001msec)
clat (usec): min=90, max=9200, avg=160.4, stdev=210.7
Interprétation : --fsync=1 force un flush à chaque écriture, approchant le pire cas de comportement de commit. La moyenne est intéressante ; le max et la queue d’attente sont ce que ressentent vos utilisateurs.
Task 8: Compare behavior with sync=disabled on a disposable dataset
cr0x@server:~$ sudo zfs create tank/test_nodur
cr0x@server:~$ sudo zfs set sync=disabled tank/test_nodur
cr0x@server:~$ fio --name=syncwrite --filename=/tank/test_nodur/syncwrite.bin \
--rw=write --bs=4k --iodepth=1 --numjobs=1 --direct=1 \
--fsync=1 --size=1G --runtime=15 --time_based=1
...
write: IOPS=42000, BW=164MiB/s (172MB/s)(2462MiB/15001msec)
clat (usec): min=18, max=480, avg=22.7, stdev=7.1
Interprétation : Ce delta montre exactement ce que vous sacrifiez : l’accusé de réception durable. Considérez ce résultat comme un outil de diagnostic, pas comme une « solution ». Si la seule façon d’être rapide est de mentir, la vraie correction est d’améliorer le chemin sync (souvent le SLOG).
Task 9: Inspect whether datasets are using zvols (common for VM storage)
cr0x@server:~$ zfs list -t volume -o name,volsize,volblocksize,sync,logbias
NAME VOLSIZE VOLBLOCKSIZE SYNC LOGBIAS
tank/vm-001 120G 16K standard latency
tank/vm-002 200G 16K disabled latency
Interprétation : Les zvols portent souvent des patterns IO VM. Notez tout sync=disabled surprenant. Notez aussi volblocksize — il influence l’amplification IO et la latence.
Task 10: Check logbias (latency vs throughput preference)
cr0x@server:~$ zfs get -r logbias tank/vm
NAME PROPERTY VALUE SOURCE
tank/vm logbias latency default
Interprétation : logbias=latency encourage l’utilisation du périphérique de log pour les écritures synchrones. throughput peut réduire l’utilisation du log dans certains cas. Ce n’est pas un substitut à un sync correct, mais cela peut influer sur le comportement pour certaines charges.
Task 11: Confirm compression and recordsize (they can change the sync story indirectly)
cr0x@server:~$ zfs get compression,recordsize tank/nfs
NAME PROPERTY VALUE SOURCE
tank/nfs compression lz4 local
tank/nfs recordsize 128K default
Interprétation : La compression peut réduire l’IO physique (souvent positif), mais elle augmente le travail CPU. Si votre problème « sync trop lent » est en réalité une saturation CPU pendant les commits TXG, vous poursuivrez la mauvaise piste si vous ne mesurez pas.
Task 12: Check real-time CPU pressure and IO wait during sync storms
cr0x@server:~$ vmstat 1 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 712344 89244 3821000 0 0 8 420 980 1900 12 6 78 4 0
5 3 0 701112 89244 3818200 0 0 0 8200 1200 2400 10 7 55 28 0
3 2 0 700980 89244 3818500 0 0 0 7900 1180 2300 11 7 56 26 0
Interprétation : Une hausse de wa (IO wait) durant des périodes sync-heavy suggère que le chemin stockage bloque le progrès CPU. Si wa est bas mais la latence élevée, vous pourriez faire face à du queueing, au comportement de flush des périphériques, ou à un périphérique de log saturé.
Task 13: Spot network filesystems forcing sync semantics (NFS server angle)
cr0x@server:~$ sudo nfsstat -s
Server rpc stats:
calls badcalls badfmt badauth badclnt
18233990 0 0 0 0
Server nfs v4:
null compound
0 11239821
Server nfs v3:
null getattr setattr lookup access
0 226001 8402 110240 90412
commit write create mkdir remove
340882 901220 4800 220 1900
Interprétation : Une forte activité NFS commit est un indice : les clients exigent des sémantiques de stockage stable. Si les commits sont fréquents et lents, votre chemin ZIL/SLOG compte plus que votre débit global.
Task 14: Verify the log devices are actually doing work (or not)
cr0x@server:~$ iostat -x 1 5 | egrep 'nvme2n1|nvme3n1|nvme0n1'
nvme2n1 0.00 740.00 0.00 56000.00 0.00 74.20 0.02 0.35 3.10 0.20 74.9
nvme3n1 0.00 735.00 0.00 55800.00 0.00 73.80 0.02 0.34 3.00 0.19 75.1
nvme0n1 55.00 120.00 8200.00 15400.00 3.40 15.30 0.10 0.80 2.10 0.40 25.0
Interprétation : Si les périphériques de log montrent de forts taux d’écriture et une forte utilisation, ils sont dans le chemin chaud. S’ils montrent une activité quasi nulle sous une charge sync-heavy, soit la charge n’est pas réellement sync, soit le dataset n’utilise pas standard/always, soit la configuration est différente de ce que vous pensez.
Playbook de diagnostic rapide (ce qu’il faut vérifier d’abord, ensuite, puis)
Quand « ZFS est lent » déclenche votre pager, vous n’avez pas de temps pour la philosophie. Vous avez besoin d’une séquence de triage qui trouve le goulot d’étranglement rapidement.
Premier : Déterminez si la douleur est liée au sync
- Vérifiez les propriétés
syncdes datasets sur le chemin chaud (zfs get -r syncsur les datasets/zvols concernés). - Surveillez
zpool iostat -v 1et cherchez la dominance d’écriture des dispositifs de log (ou des vdevs principaux luttant avec de petites écritures). - Sur Linux, échantillonnez la fréquence des
fsync/fdatasyncavecperf trace(ou logs/metrics applicatives).
Décision : Si vous observez des appels sync fréquents et une forte activité/latence du log, c’est un goulot sur le chemin sync. Si non, ne perdez pas de temps à blâmer sync.
Second : Localisez le point d’étranglement (SLOG vs vdevs principaux vs CPU)
- Si vous avez un SLOG : inspectez sa classe de périphérique, sa santé et son utilisation. Utilisez
iostat -xetzpool iostat -vpour voir s’il est saturé. - Si vous n’avez pas de SLOG : vérifiez la latence des vdevs principaux sous charge sync-heavy. Des disques spinning effectuant des écritures synchrones peuvent ressembler à des « gels aléatoires » pour les applications.
- Vérifiez la saturation CPU et l’IO wait (
vmstat,top). Un système occupé peut faire paraître les commits sync comme un problème de stockage alors que c’est de l’ordonnancement et de la contention.
Troisième : Validez les attentes de durabilité avant de « réparer » la performance
- Identifiez la classe de charge : base de données, disques VM, répertoires NFS utilisateur, cache de build, scratch, réplicas éphémères.
- Demandez : quelle fenêtre de perte est acceptable en cas de coupure soudaine ? « Aucune » est une réponse valide.
- Ce n’est qu’ensuite que vous pouvez considérer des changements comme ajouter un SLOG, le miroiter, ajuster les datasets, ou (rarement) désactiver sync pour des données réellement jetables.
Erreurs courantes (avec symptômes et corrections spécifiques)
Mistake 1: Disabling sync on VM or database storage “because it’s slow”
Symptômes : Les benchmarks et la latence s’améliorent énormément ; plus tard, après un crash ou un événement de coupure, vous observez une corruption de système de fichiers, des transactions DB « commises » manquantes, ou un état applicatif incohérent.
Correction : Rétablissez sync=standard (ou always si approprié). Investissez dans un SLOG correct et/ou réduisez la pression sync au niveau applicatif via des réglages supportés (avec acceptation explicite du risque).
Mistake 2: Buying a SLOG that is fast but not power-loss safe
Symptômes : Excellentes performances ; plus tard, des problèmes d’intégrité des données après coupure de courant ; ou découverte que le périphérique ignore les flushs.
Correction : Utilisez des périphériques protégés contre la perte de courant et conçus pour des écritures soutenues à faible latence. Miroirez le SLOG lorsque l’intégrité de la charge est importante.
Mistake 3: Expecting SLOG to speed up everything
Symptômes : Vous ajoutez un SLOG et ne voyez aucune amélioration ; ou seulement une petite amélioration ; les utilisateurs se plaignent encore de la latence de lecture.
Correction : Confirmez que la charge a un problème d’écritures synchrones. Si elle est orientée lecture, concentrez-vous sur la taille de l’ARC, le nombre de vdevs, le recordsize et la performance des périphériques sous-jacents — pas le SLOG.
Mistake 4: Tuning without measuring tail latency
Symptômes : La latence moyenne a l’air correcte ; les utilisateurs se plaignent de blocages ; freeze des VM ; pics de commit DB.
Correction : Mesurez et tracez les percentiles (p95/p99). Les goulots sync apparaissent souvent comme de la latence en queue d’attente due au queueing et aux tempêtes de flush.
Mistake 5: Mixing “critical” and “throwaway” data on the same dataset policy
Symptômes : Quelqu’un configure sync=disabled pour un répertoire cache et l’applique accidentellement à un dataset parent utilisé pour des données réelles ; ou l’héritage change après une refactorisation.
Correction : Utilisez des datasets séparés avec des propriétés explicites. Vérifiez avec zfs get -r -o name,property,value,source et intégrez des vérifications dans le provisioning.
Mistake 6: Ignoring that NFS semantics can force sync behavior
Symptômes : Les clients NFS affichent une forte latence ; le CPU/ réseau du serveur semblent corrects ; le débit de stockage n’est pas saturé ; pourtant les opérations bloquent.
Correction : Inspectez les patterns commit/write NFS et assurez-vous que le chemin sync du serveur est rapide et sûr (SLOG + périphériques appropriés). Ne « corrigez » pas cela en désactivant sync sauf si les données sont vraiment jetables.
Listes de contrôle / plan pas à pas
Checklist A: Decide the correct sync mode per dataset
- Classez les données : état critique, données utilisateur, base de données, images VM, cache, scratch, éphémère répliqué.
- Définissez la perte acceptable en cas de crash : aucune, secondes, minutes, « peu importe ». Mettez-le par écrit.
- Définissez
sync=standardpour la plupart des données réelles. - Considérez
sync=alwaysuniquement si vous devez imposer la durabilité indépendamment du comportement de l’appelant. - Utilisez
sync=disableduniquement pour des datasets explicitement jetables (et isolez-les).
Checklist B: Add a SLOG safely (when justified)
- Prouvez que vous êtes limité par les sync : mesurez le taux de
fsyncet l’utilisation ZIL/SLOG. - Choisissez des périphériques avec protection contre la perte de courant et une latence prévisible sous écritures soutenues.
- Miroirez le SLOG pour des charges importantes.
- Ajoutez-le et validez avec des tests de charge réels, pas seulement des synthétiques.
Step-by-step: Implement a dedicated “safe fast sync” dataset
Ceci est un schéma courant pour des exports NFS ou des volumes de bases de données où vous voulez la durabilité avec des performances raisonnables.
cr0x@server:~$ sudo zfs create tank/prod_safe
cr0x@server:~$ sudo zfs set sync=standard tank/prod_safe
cr0x@server:~$ sudo zfs set logbias=latency tank/prod_safe
cr0x@server:~$ sudo zfs set atime=off tank/prod_safe
cr0x@server:~$ sudo zfs set compression=lz4 tank/prod_safe
cr0x@server:~$ zfs get -o name,property,value,source sync,logbias,atime,compression tank/prod_safe
NAME PROPERTY VALUE SOURCE
tank/prod_safe sync standard local
tank/prod_safe logbias latency local
tank/prod_safe atime off local
tank/prod_safe compression lz4 local
Interprétation : Cela ne « garantit » pas la vitesse, mais aligne le comportement ZFS sur une stratégie sync basse-latence tout en conservant la durabilité.
Step-by-step: Create an explicitly disposable dataset (and label it like it’s radioactive)
cr0x@server:~$ sudo zfs create tank/scratch_ephemeral
cr0x@server:~$ sudo zfs set sync=disabled tank/scratch_ephemeral
cr0x@server:~$ sudo zfs set compression=off tank/scratch_ephemeral
cr0x@server:~$ sudo zfs set atime=off tank/scratch_ephemeral
cr0x@server:~$ zfs get -o name,property,value,source sync,compression tank/scratch_ephemeral
NAME PROPERTY VALUE SOURCE
tank/scratch_ephemeral sync disabled local
tank/scratch_ephemeral compression off local
Interprétation : Rendez le périmètre d’impact évident. Gardez-le en dehors des chemins d’héritage utilisés par des données réelles.
FAQ
1) Does sync=disabled mean “I might lose the last few seconds”?
Ça peut être pire. Vous pouvez perdre des données que l’application croyait avoir commit. Cela peut causer une corruption logique : une base ou un service peut accuser réception d’une transaction puis l’oublier après un crash. « Quelques secondes » n’est pas une borne fiable à moins que toute la pile soit conçue pour ce mode de défaillance.
2) If I have a UPS, can I safely disable sync?
Un UPS réduit le risque mais ne l’élimine pas. Les kernel panic, réinitialisations de contrôleur, bugs de firmware, coupures accidentelles et pannes d’alimentation redondantes existent toujours. De plus, un UPS n’aide pas si un périphérique ment sur l’achèvement des flushs. Si vous avez besoin de garanties de durabilité, considérez l’UPS comme une défense en profondeur, pas comme un substitut.
3) Do I need a SLOG on an all-NVMe pool?
Pas toujours. Certains pools NVMe ont une latence suffisante pour que le ZIL sur pool soit acceptable. Le facteur décisif est la latence des écritures synchrones sous votre charge et le comportement de flush des périphériques. Mesurez avant d’acheter du matériel.
4) Should the SLOG be large?
Généralement non. Le SLOG contient un journal à court terme des opérations sync en attente jusqu’au commit TXG. La cohérence de latence et la sécurité en cas de perte de courant comptent bien plus que la capacité. Surdimensionner est courant et sans grand mal, mais rarement le goulot ou la victoire.
5) What’s the difference between ZIL and SLOG again?
Le ZIL est un mécanisme : le journal d’intention utilisé pour satisfaire les sémantiques sync. Le SLOG est un périphérique : un emplacement dédié pour stocker les enregistrements ZIL, idéalement plus rapide et plus sûr que le pool principal pour ce type d’écriture.
6) Why is NFS slow on my ZFS server even though local writes are fast?
Les clients NFS demandent souvent des écritures stables. Les tests locaux utilisent souvent de l’IO bufferisée/asynchrone qui n’oblige pas les flushs. Si votre chemin ZIL/SLOG est lent, la latence NFS semblera terrible tandis que le débit global a l’air correct.
7) Is sync=always safer than sync=standard?
Ça peut l’être, dans le sens où il force la durabilité même si l’application oublie de la demander. Mais il peut aussi causer de lourdes pénalités de performance. Utilisez-le quand vous avez une raison spécifique de ne pas faire confiance aux appelants — et quand votre chemin sync (SLOG ou pool principal) peut le supporter.
8) Can I “fix” sync latency by changing recordsize or compression?
Parfois indirectement. La latence sync porte souvent sur le comportement de flush/commit et la latence des périphériques. Mais si les commits TXG causent du backpressure, le CPU et l’amplification d’écriture peuvent compter. Ne devinez pas : mesurez la latence des appels sync, la latence des périphériques et le comportement TXG ensemble.
9) If I mirror my SLOG, does that double latency?
Ça peut l’augmenter un peu, parce que les écritures doivent être commit sur les deux périphériques. Mais avec des périphériques basse-latence appropriés, un SLOG miroir est souvent encore bien plus rapide que logger sur des vdevs principaux plus lents — et il améliore la résilience contre la défaillance du périphérique de log.
10) What’s the most operator-friendly rule of thumb?
Si la charge ouvrirait un ticket lorsqu’elle perd une écriture « commitée », n’utilisez pas sync=disabled. Au lieu de cela, rendez le chemin sync rapide de la manière honnête : bons périphériques, bon SLOG (si nécessaire), et conception des datasets en connaissance de la charge.
Conclusion
Le sync de ZFS est l’un de ces réglages qui ressemble à un code de triche parce qu’il peut l’être. Il peut aussi être un piège. La propriété ne concerne pas « rendre ZFS plus rapide ». Elle concerne la façon dont ZFS honorera (ou réécrira silencieusement) le contrat de durabilité de l’appelant.
L’état d’esprit en production est de traiter sync comme une décision de politique, pas comme un hack de tuning. Commencez par identifier qui demande des sémantiques synchrones et pourquoi. Mesurez le chemin ZIL/SLOG, pas seulement le débit global. Si vous avez besoin à la fois de performance et d’une vérité dans l’accusé de réception, investissez dans un chemin d’écriture synchrone approprié et gardez les réglages alignés avec la promesse métier que vos systèmes font.