ZFS sync : le réglage qui peut vous rendre rapide… et dangereux

Cet article vous a aidé ?

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 :

  • sync ne 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.
  • sync peut 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 :

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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

  1. Vérifiez les propriétés sync des datasets sur le chemin chaud (zfs get -r sync sur les datasets/zvols concernés).
  2. Surveillez zpool iostat -v 1 et cherchez la dominance d’écriture des dispositifs de log (ou des vdevs principaux luttant avec de petites écritures).
  3. Sur Linux, échantillonnez la fréquence des fsync/fdatasync avec perf 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)

  1. Si vous avez un SLOG : inspectez sa classe de périphérique, sa santé et son utilisation. Utilisez iostat -x et zpool iostat -v pour voir s’il est saturé.
  2. 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.
  3. 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

  1. Identifiez la classe de charge : base de données, disques VM, répertoires NFS utilisateur, cache de build, scratch, réplicas éphémères.
  2. Demandez : quelle fenêtre de perte est acceptable en cas de coupure soudaine ? « Aucune » est une réponse valide.
  3. 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

  1. Classez les données : état critique, données utilisateur, base de données, images VM, cache, scratch, éphémère répliqué.
  2. Définissez la perte acceptable en cas de crash : aucune, secondes, minutes, « peu importe ». Mettez-le par écrit.
  3. Définissez sync=standard pour la plupart des données réelles.
  4. Considérez sync=always uniquement si vous devez imposer la durabilité indépendamment du comportement de l’appelant.
  5. Utilisez sync=disabled uniquement pour des datasets explicitement jetables (et isolez-les).

Checklist B: Add a SLOG safely (when justified)

  1. Prouvez que vous êtes limité par les sync : mesurez le taux de fsync et l’utilisation ZIL/SLOG.
  2. Choisissez des périphériques avec protection contre la perte de courant et une latence prévisible sous écritures soutenues.
  3. Miroirez le SLOG pour des charges importantes.
  4. 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.

← Précédent
DNS local pour utilisateurs VPN : stoppez les fuites DNS et les échecs de routage fractionné
Suivant →
Debian 13 : votre serveur ne démarre plus après des mises à jour — le rollback propre de GRUB qui fonctionne vraiment

Laisser un commentaire