Pics de latence ZFS : la checklist pour identifier la cause

Cet article vous a aidé ?

Les pics de latence sont le type de problème de stockage qui fait dire des choses étranges dans les canaux d’incident même aux personnes compétentes. Tout va bien… jusqu’à ce que ça ne le soit plus. Votre p99 d’API grimpe à 800ms, votre base de données commence à « attendre l’IO », et votre serveur ZFS a l’air indifférent.

ZFS n’est pas « lent au hasard ». Il fait généralement quelque chose de très précis à une couche donnée : écritures synchrones, commit TXG, mise en file des périphériques, libération de mémoire, scrub/resilver, ou une inadéquation de charge malchanceuse. L’astuce consiste à arrêter de deviner et à lancer une checklist qui rétrécit le goulot d’étranglement en minutes, pas en heures.

Playbook de diagnostic rapide (premier/deuxième/troisième)

Ceci est la séquence « j’ai cinq minutes avant que mon chef rejoigne l’appel ». N’optimisez rien encore. Ne touchez pas aux propriétés comme un DJ. Identifiez simplement la couche où le temps se perd.

Premier : confirmer qu’il s’agit de latence de stockage, pas d’ordonnancement CPU ou de réseau

  1. Vérifiez la charge système et l’attente IO. Si le CPU est saturé ou si vous thrashiez la mémoire, le stockage paraîtra coupable alors qu’il ne l’est pas forcément.

    cr0x@server:~$ uptime
     14:22:18 up 18 days,  3:11,  2 users,  load average: 7.81, 7.34, 6.92
    cr0x@server:~$ vmstat 1 5
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
     2  1      0  82120  15640 912340    0    0   120   980  540  890 12  5 73 10  0
     1  2      0  81288  15640 905112    0    0   240  2030  620 1010 10  6 62 22  0
    

    Ce que ça signifie : Un wa élevé (IO wait) suggère que le CPU est souvent bloqué en attente d’IO. Un b élevé signifie des processus bloqués, souvent sur le disque.

    Décision : Si des pics de wa coïncident avec des pics de latence applicative, passez aux contrôles spécifiques à ZFS. Si us/sy est saturé, examinez d’abord les goulots CPU (compression, checksums, chiffrement).

  2. Vérifiez le réseau si c’est NFS/SMB/iSCSI.

    cr0x@server:~$ ss -ti | head -n 15
    State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
    ESTAB 0      0      10.0.0.12:2049    10.0.2.45:51712  timer:(keepalive,38min,0) ino:0 sk:3b2
    	 cubic wscale:7,7 rto:204 retrans:0/0 rtt:0.337/0.012 ato:40 mss:1448 pmtu:1500 rcvmss:1448 advmss:1448 cwnd:10 bytes_sent:818244 bytes_acked:818244 bytes_received:94412 segs_out:571 segs_in:558 send 343Mb/s lastsnd:12 lastrcv:12 lastack:12 pacing_rate 686Mb/s
    

    Ce que ça signifie : Les retransmissions et de grandes variations de RTT peuvent imiter des « pics de stockage ».

    Décision : Si le réseau est propre (RTT stable, pas de retransmissions), concentrez-vous sur le disque/ZFS.

Deuxième : déterminer si le pic est lié aux écritures sync/TXG

  1. Surveillez la latence ZFS au niveau du pool.

    cr0x@server:~$ zpool iostat -v -l 1 10
                                  capacity     operations     bandwidth     total_wait     disk_wait
    pool                        alloc   free   read  write   read  write   read  write   read  write
    tank                        3.12T  1.45T    210   9800  12.3M  402M   2.1ms  85ms   1.9ms  82ms
      raidz2-0                  3.12T  1.45T    210   9800  12.3M  402M   2.1ms  85ms   1.9ms  82ms
        sda                         -      -     20   1250  1.3M  50.1M  1.8ms  88ms   1.7ms  84ms
        sdb                         -      -     22   1210  1.4M  49.6M  2.0ms  86ms   1.8ms  83ms
        sdc                         -      -     19   1220  1.2M  50.0M  2.1ms  84ms   1.9ms  81ms
    

    Ce que ça signifie : total_wait correspond à ce que les appelants ressentent ; disk_wait isole le temps de service des périphériques. Si total_wait est élevé mais disk_wait faible, vous avez de la mise en file au‑dessus des disques (TXG, throttling, contention).

    Décision : Si l’attente d’écriture monte à des dizaines/centaines de ms pendant les pics, suspectez les écritures sync, le SLOG, la pression de commit TXG ou la saturation du pool.

Troisième : rechercher les IO de maintenance et la contention évidente

  1. Un scrub/resilver est‑il en cours ?

    cr0x@server:~$ zpool status -v tank
      pool: tank
     state: ONLINE
    status: One or more devices is currently being scrubbed.
      scan: scrub in progress since Mon Dec 23 02:01:13 2025
            1.22T scanned at 1.02G/s, 438G issued at 365M/s, 3.12T total
            0B repaired, 14.04% done, 0:02:45 to go
    config:
    
            NAME        STATE     READ WRITE CKSUM
            tank        ONLINE       0     0     0
              raidz2-0  ONLINE       0     0     0
                sda     ONLINE       0     0     0
                sdb     ONLINE       0     0     0
                sdc     ONLINE       0     0     0
    

    Ce que ça signifie : Les scrubs et resilvers sont de véritables tempêtes IO. Ils changent aussi les profils d’IO (plus de lectures, plus de métadonnées).

    Décision : Si les pics coïncident avec des fenêtres de scrub/resilver, replanifiez, ajustez le comportement du scrub ou prévoyez suffisamment de marge pour survivre à la maintenance.

Un modèle mental utilisable de la latence ZFS

Les pics de latence ZFS ne proviennent rarement d’un réglage magique. Ils viennent d’un pipeline où n’importe quelle étape peut se bloquer :

  • Sémantique applicative : écritures sync vs async, rafales fsync, checkpoints de bases de données.
  • Couche système de fichiers : propriétés de dataset (recordsize, compression, atime), comportement des métadonnées et petits blocs, vdevs spéciaux.
  • ARC et mémoire : les hits de cache sont rapides ; les misses et le churn d’éviction ne le sont pas. La pression mémoire rend tout plus agressif.
  • TXG (groupes de transactions) : ZFS regroupe les changements et les commit. Quand le travail de commit s’accumule, vous pouvez voir des pauses périodiques ou des vagues de latence d’écriture.
  • ZIL/SLOG (écritures sync) : les écritures synchrones sont acquittées après avoir été journalisées en toute sécurité. Si le périphérique de journal est lent, votre application apprend de nouveaux mots.
  • Topologie vdev et disques : math RAIDZ, profondeur de file, comportements SMR, bugs de firmware, politiques de write cache.
  • Couche de périphérique bloc : choix du scheduler, multipath, HBAs, timeouts de disque.

Quand quelqu’un dit « ZFS plante », demandez : où se produisent les pics ? Sur la lecture ? l’écriture ? seulement les écritures sync ? seulement les métadonnées ? seulement quand le pool est à 80 % ? seulement pendant les sauvegardes ? Votre travail est de transformer « instable » en un graphique avec un coupable.

Une opinion qui vous fera gagner du temps : traitez ZFS comme une base de données. Il a son propre batching (TXGs), son logging (ZIL), son cache (ARC) et son travail d’arrière‑plan (scrub/resilver). Si vous ne tuneriez pas une base de données en changeant des boutons au hasard, ne le faites pas avec ZFS non plus.

Idée paraphrasée de Werner Vogels (CTO d’Amazon) : « Tout échoue, tout le temps ; concevez des systèmes qui l’anticipent. » Cela inclut votre budget de latence pour le stockage.

Blague n°1 : ZFS n’a pas de « sautes d’humeur ». Il a de la « comptabilité d’E/S ». Moins drôle, mais plus actionnable.

Faits intéressants et brève histoire (pourquoi ZFS se comporte ainsi)

  • ZFS a fait ses débuts au milieu des années 2000 avec le checksum de bout en bout comme fonctionnalité de premier plan, pas un add‑on. Ce choix influence la latence parce que chaque bloc lu peut impliquer une vérification de checksum.
  • Le ZIL existe même sans SLOG dédié. Si vous n’ajoutez pas de périphérique de journal, ZFS utilise de l’espace sur les périphériques du pool. Votre configuration « sans SLOG » a toujours un journal sync ; il est juste plus lent et concurrence les écritures normales.
  • Le commit TXG est périodique. ZFS regroupe les données et métadonnées modifiées, puis les vide. Ce regroupement augmente le débit mais peut créer des pulsations rythmiques de latence sous une charge soutenue.
  • Copy-on-write est à la fois une fonctionnalité et un coût. Il empêche les réécritures en place (bon pour l’intégrité et les snapshots) mais peut augmenter la fragmentation et le travail des métadonnées avec le temps, affectant la latence maximale.
  • RAIDZ n’est pas un « RAID gratuit ». Il économise des disques mais rend les petites écritures aléatoires coûteuses (patterns read-modify-write). La latence en queue est la première à en souffrir.
  • La réalité du secteur 4K est arrivée après la conception de nombreux baies. Un mauvais choix d’ashift (ou des hypothèses 512e anciennes) peut transformer des « écritures normales » en IO amplifiée.
  • L’ARC a été conçu pour être adaptatif, pas discret. Il mangera volontiers de la mémoire pour le cache ; si votre charge a besoin de RAM ailleurs (VMs, page cache, bases de données), la pression résultante peut se manifester comme de la gigue de stockage.
  • Les vdevs spéciaux sont l’histoire moderne des « SSD pour métadonnées » de ZFS. Ils peuvent réduire dramatiquement la latence des métadonnées—à moins qu’ils ne saturent ou ne tombent en panne, auquel cas l’expérience du pool change.
  • La compression est devenue courante dans ZFS avant que ce soit « cool ». Elle échange cycles CPU contre moins d’IO ; sur NVMe rapide, le CPU devient le goulot plus souvent que prévu, provoquant des symptômes de « latence de stockage ».

Checklists / plan pas à pas (avec commandes)

Ceci est l’événement principal : tâches pratiques à exécuter pendant un incident et à reproduire en postmortem calme. Chaque tâche inclut (1) la commande, (2) ce que signifie la sortie, (3) la décision à prendre.

Tâche 1 : Capturer la latence au niveau du pool et séparer la mise en file du temps de service disque

cr0x@server:~$ zpool iostat -l 1 30
                              capacity     operations     bandwidth     total_wait     disk_wait
pool                        alloc   free   read  write   read  write   read  write   read  write
tank                        3.12T  1.45T    320   9200  18.2M  380M   3.2ms  96ms   2.8ms  91ms
tank                        3.12T  1.45T    310   9300  17.8M  387M   2.9ms  140ms  2.6ms  132ms
tank                        3.12T  1.45T    290   9100  16.4M  376M   3.0ms  35ms   2.7ms  31ms

Ce que ça signifie : Quand total_wait explose, c’est ce que l’utilisateur voit. Si disk_wait suit, ce sont les disques (ou les HBA) qui sont lents. Si disk_wait reste modeste tandis que total_wait monte, vous êtes goulot d’étranglement au‑dessus du disque : throttling, congestion TXG, contention ZIL, verrous.

Décision : Des pics pilotés par disk_wait vous envoient aux contrôles matériel/périphérique/queues. Des pics seulement sur total_wait vous envoient aux vérifications sync/TXG/ARC.

Tâche 2 : Trouver le vdev coupable ou un disque lent

cr0x@server:~$ zpool iostat -v -l 2 10 tank
                              capacity     operations     bandwidth     total_wait     disk_wait
pool                        alloc   free   read  write   read  write   read  write   read  write
tank                        3.12T  1.45T    300   9100  16.8M  375M   3.0ms  72ms   2.7ms  68ms
  raidz2-0                  3.12T  1.45T    300   9100  16.8M  375M   3.0ms  72ms   2.7ms  68ms
    sda                         -      -     30   1200  1.8M  48.9M  2.6ms  70ms   2.4ms  66ms
    sdb                         -      -     29   1180  1.7M  48.2M  2.7ms  72ms   2.5ms  69ms
    sdc                         -      -     28   1190  1.6M  48.6M  35ms   250ms  33ms   240ms

Ce que ça signifie : Un périphérique avec une latence 10× entraîne un vdev RAIDZ vers le bas parce que la mathématique de parité force de la coordination. Les miroirs souffrent aussi : les lectures peuvent éviter un côté lent, les écritures non.

Décision : Si un disque est l’outlier, vérifiez SMART, le câblage, le chemin HBA. Remplacez le disque s’il continue de provoquer des pics. Ne « tunez » pas ZFS autour d’un disque en fin de vie.

Tâche 3 : Confirmer si les écritures sont synchrones (et si la charge les force)

cr0x@server:~$ zfs get -r sync tank
NAME        PROPERTY  VALUE  SOURCE
tank        sync      standard  default
tank/db     sync      standard  inherited from tank
tank/vm     sync      always    local

Ce que ça signifie : sync=always force chaque écriture à se comporter comme une écriture sync. Certaines charges en ont besoin (bases de données), beaucoup non (logs en masse). standard obéit à l’application (fsync/O_DSYNC).

Décision : Si un dataset est en sync=always sans raison claire, remettez‑le en standard après avoir confirmé les besoins de durabilité de l’application. Si c’est vraiment requis, fournissez un SLOG de qualité ou acceptez la latence.

Tâche 4 : Vérifier si vous avez un SLOG et s’il est sain

cr0x@server:~$ zpool status tank
  pool: tank
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0
        logs
          nvme0n1p2 ONLINE       0     0     0

Ce que ça signifie : Si le pool a une section logs, vous avez un périphérique de journal séparé. Sinon, les écritures sync atterrissent sur les vdevs principaux. Aussi : un SLOG ONLINE peut pourtant être lent.

Décision : Si la latence sync vous tue et qu’il n’y a pas de SLOG, ajoutez‑en un (miroir si la durabilité importe). S’il y a un SLOG, faites‑le passer au banc d’essai ; un NVMe grand public bon marché peut avoir une latence tail catastrophique sous les exigences d’alimentation protégée.

Tâche 5 : Valider recordsize et volblocksize du dataset par rapport à la charge

cr0x@server:~$ zfs get recordsize,volblocksize,primarycache,logbias tank/vm tank/db
NAME      PROPERTY      VALUE   SOURCE
tank/vm   recordsize    128K    inherited from tank
tank/vm   volblocksize  -       -
tank/vm   primarycache  all     default
tank/vm   logbias       latency default
tank/db   recordsize    16K     local
tank/db   volblocksize  -       -
tank/db   primarycache  all     default
tank/db   logbias       latency local

Ce que ça signifie : Les bases de données aiment souvent recordsize 8K–16K pour des fichiers ; les images VM peuvent préférer volblocksize ajusté à la création du zvol (valeurs courantes 8K–64K selon l’hyperviseur). Des tailles inadaptées augmentent read-modify-write et la pression sur les métadonnées.

Décision : Si vous voyez un décalage, planifiez une migration (on ne peut pas changer volblocksize après création). Ne faites pas ça en plein incident sauf si vous aimez les heures sup.

Tâche 6 : Vérifier le remplissage du pool et la pression de fragmentation

cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
NAME  SIZE  ALLOC  FREE  CAP  FRAG  HEALTH
tank  4.50T 3.12T 1.38T  69%   41%  ONLINE

Ce que ça signifie : Un cap élevé (surtout au‑dessus d’environ 80–85%) et une fragmentation élevée corrèlent souvent avec une pire latence de queue, particulièrement sur des HDD RAIDZ. ZFS a moins de segments libres contigus ; l’allocation devient plus coûteuse.

Décision : Si le cap est élevé, libérez de l’espace (supprimez, déplacez, agrandissez). Si la frag est élevée et la performance s’effondre, envisagez de réécrire les données (send/recv vers un pool frais) ou ajoutez des vdevs pour augmenter les choix d’allocation.

Tâche 7 : Vérifier la taille ARC, le ratio de hit et les signaux de pression mémoire

cr0x@server:~$ arcstat 1 5
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
14:25:01   820    44      5    10    1    34    4     0    0   62G   64G
14:25:02   910   210     23    80    9   130   14     0    0   62G   64G
14:25:03   840   190     22    70    8   120   14     0    0   58G   64G
14:25:04   870    55      6    12    1    43    5     0    0   58G   64G

Ce que ça signifie : Des pics de miss% et un ARC qui rétrécit peuvent indiquer une pression mémoire ou un changement de charge. Quand l’ARC ne peut plus contenir les données chaudes, les lectures deviennent de l’IO disque réel, et la latence devient spiky.

Décision : Si l’ARC est volatile et que miss% bondit pendant les incidents, vérifiez la mémoire globale, le comportement de reclaim, et si autre chose (VMs, conteneurs) consomme la RAM. Envisagez de réserver de la mémoire, ajuster arc_max ou déplacer le locataire bruyant.

Tâche 8 : Identifier la pression d’écritures sync via les statistiques ZIL

cr0x@server:~$ kstat -p | egrep 'zfs:0:zil:|zfs:0:vdev_sync' | head
zfs:0:zil:zil_commit_count                        184220
zfs:0:zil:zil_commit_writer_count                  12011
zfs:0:zil:zil_commit_waiter_count                  31255
zfs:0:vdev_sync:vdev_sync_write_bytes              98342199296

Ce que ça signifie : Des compteurs de commit et waiter en hausse pointent vers une forte activité sync. Si les waiters s’accumulent, les applications bloquent sur les commits de journal.

Décision : Si la pression sync est élevée, validez la latence du SLOG, les réglages logbias, et si l’app effectue trop de fsync (ou fonctionne en mode « sûr mais lent »).

Tâche 9 : Confirmer si un scrub, resilver ou une récupération d’erreur de périphérique consomme l’IO

cr0x@server:~$ zpool status tank | sed -n '1,25p'
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 0 days 03:22:11 with 0 errors on Sun Dec 22 03:22:11 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0

Ce que ça signifie : Un statut de pool propre n’exclut pas l’IO d’arrière‑plan, mais écarte les tâches de maintenance évidentes.

Décision : Si un scan est actif pendant les pics, décidez de le mettre en pause (dans certains environnements), de le replanifier ou d’accepter l’impact comme coût d’intégrité.

Tâche 10 : Vérifier la mise en file et la latence par disque au niveau bloc Linux

cr0x@server:~$ iostat -x 1 5
Linux 6.6.0 (server) 	12/25/2025 	_x86_64_	(32 CPU)

Device            r/s     w/s   rMB/s   wMB/s avgrq-sz avgqu-sz await r_await w_await  svctm  %util
sda              25.0  1200.0     1.6    49.0    86.0     9.2  62.0   18.0   63.0   0.8   98.0
sdb              24.0  1180.0     1.5    48.3    86.0     8.9  60.0   17.5   61.0   0.8   97.0
sdc              23.0  1190.0     1.4    48.6    86.0    28.1  220.0  21.0  225.0   0.8   99.0

Ce que ça signifie : avgqu-sz et await montrent l’accumulation de file. %util proche de 100% indique une saturation. Un disque avec une grosse file et un await élevé est votre générateur de pics de latence.

Décision : Si la couche bloc montre le même disque outlier que ZFS, ce n’est pas un problème de réglage ZFS. Récupérez SMART, vérifiez les logs du contrôleur et préparez le remplacement.

Tâche 11 : Vérifier la santé des disques et les compteurs « ce disque vous ment »

cr0x@server:~$ smartctl -a /dev/sdc | egrep -i 'Reallocated|Pending|Uncorrect|CRC|Power_On_Hours|Temperature|Error'
Power_On_Hours          38122
Temperature_Celsius     44
Reallocated_Sector_Ct   0
Current_Pending_Sector  8
Offline_Uncorrectable   2
UDMA_CRC_Error_Count    19

Ce que ça signifie : Les secteurs pendants/inaltérables peuvent provoquer de longues tentatives internes. Les erreurs CRC signifient souvent un câblage ou un backplane défaillant, qui produit des pics de latence intermittents plutôt que des pannes nettes.

Décision : Les secteurs pendants et les erreurs inaltérables sont un signe « remplacer bientôt » ; les erreurs CRC sont un signe « réparer le chemin ». L’un ou l’autre peut expliquer des stalls périodiques de 200ms–2s.

Tâche 12 : Vérifier les propriétés de dataset qui causent silencieusement des IO supplémentaires

cr0x@server:~$ zfs get -r atime,compression,xattr,acltype,logbias tank | head -n 20
NAME      PROPERTY     VALUE     SOURCE
tank      atime        off       local
tank      compression  lz4       local
tank      xattr        sa        local
tank      acltype      posixacl  local
tank      logbias      latency   default
tank/db   atime        off       inherited from tank
tank/db   compression  lz4       inherited from tank
tank/db   xattr        sa        inherited from tank
tank/db   acltype      posixacl  inherited from tank
tank/db   logbias      latency   local

Ce que ça signifie : atime=on sur des charges majoritairement en lecture génère des écritures sur des lectures, ce qui est une forme particulière d’auto‑sabotage. La compression peut réduire l’IO mais augmenter la latence CPU. xattr=sa aide souvent les charges riches en métadonnées.

Décision : Si vous voyez atime=on sur des datasets chauds et que vous n’en avez pas besoin, désactivez‑le. Si la compression est lourde et que des pics CPU corrèlent avec la latence, envisagez d’ajuster la compression ou d’ajouter du CPU.

Tâche 13 : Vérifier si snapshots et suppressions créent un travail métadonnée pathologique

cr0x@server:~$ zfs list -t snapshot -o name,used,creation -s creation | tail -n 5
tank/db@auto-2025-12-25-0100   2.1G  Mon Dec 25 01:00 2025
tank/db@auto-2025-12-25-0200   2.2G  Mon Dec 25 02:00 2025
tank/db@auto-2025-12-25-0300   2.2G  Mon Dec 25 03:00 2025
tank/db@auto-2025-12-25-0400   2.3G  Mon Dec 25 04:00 2025
tank/db@auto-2025-12-25-0500   2.4G  Mon Dec 25 05:00 2025

Ce que ça signifie : Les snapshots sont bon marché à créer, pas toujours bon marché à conserver. De grands arbres de snapshots + réécritures constantes peuvent augmenter la fragmentation et le churn des métadonnées, qui se manifestent par de la gigue.

Décision : Si vous avez une rétention agressive de snapshots sur des datasets à fort churn, réduisez la rétention ou déplacez cette charge vers des miroirs/NVMe où le churn métadonnée est moins pénalisant.

Tâche 14 : Valider ashift et l’alignement des secteurs (le réglage « pour toujours »)

cr0x@server:~$ zdb -C tank | egrep 'ashift|path' | head -n 20
            path: '/dev/disk/by-id/ata-ST12000NM0008-2H2161_ZHZ12345'
            ashift: 12
            path: '/dev/disk/by-id/ata-ST12000NM0008-2H2161_ZHZ23456'
            ashift: 12

Ce que ça signifie : ashift=12 signifie secteurs 4K ; ashift=9 signifie 512B. Définir ashift trop bas sur des disques 4K peut créer une amplification d’écriture et une horrible latence tail.

Décision : Si ashift est incorrect, vous ne pouvez pas le « corriger » en place. Planifiez une reconstruction/migration. Mettez‑le dans le postmortem comme « nous ne referons pas ça ».

Tâche 15 : Trouver les signaux de throttling et de pression TXG (Linux OpenZFS)

cr0x@server:~$ cat /proc/spl/kstat/zfs/txgs
txg                            birth                    state                    ndirty
1064217                        1703510152               open                     2147483648
1064216                        1703510150               quiescing                1987654321
1064215                        1703510148               syncing                  1876543210

Ce que ça signifie : Plusieurs TXGs en quiescing/syncing avec des octets sales très élevés suggèrent que le système a du mal à vider. Cela peut se manifester par des pics de latence d’écriture et des stalls lorsque ZFS applique une contre‑pression.

Décision : Si les TXGs sont bloqués en syncing, réduisez le taux de salissement (throttling applicatif, tune des rafales d’écriture), augmentez la performance des vdevs, ou réduisez les tâches d’arrière‑plan concurrentes. Ne vous contentez pas d’augmenter les limites de données sales et d’espérer.

Tâche 16 : Vérifier la santé et l’utilisation du special vdev (métadonnées sur SSD)

cr0x@server:~$ zpool status -v tank | sed -n '1,80p'
  pool: tank
 state: ONLINE
config:

        NAME           STATE     READ WRITE CKSUM
        tank           ONLINE       0     0     0
          raidz2-0     ONLINE       0     0     0
            sda        ONLINE       0     0     0
            sdb        ONLINE       0     0     0
            sdc        ONLINE       0     0     0
        special
          mirror-1     ONLINE       0     0     0
            nvme1n1    ONLINE       0     0     0
            nvme2n1    ONLINE       0     0     0

Ce que ça signifie : Un special vdev contient les métadonnées (et éventuellement petits blocs). S’il est malsain ou sous-dimensionné, les opérations métadonnées peuvent piquer même si les données bulk vont bien. Aussi : si le special vdev échoue et que vous perdez la redondance, le risque du pool monte en flèche.

Décision : Si un special vdev est présent, traitez‑le comme une infrastructure de niveau 0. Surveillez‑le comme vous surveillez le WAL de votre base de données. S’il est petit ou lent, corrigez cela avant de chasser des fantômes.

Tâche 17 : Corréler le comportement sync de l’application avec les pics de stockage

cr0x@server:~$ pidstat -d 1 5 | egrep 'postgres|mysqld|qemu|java' || true
14:28:11      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
14:28:12      113      2218      0.00  402112.00  1024.00     312  postgres
14:28:13      113      2218      0.00  398740.00   980.00     411  postgres

Ce que ça signifie : L’augmentation de iodelay indique que le processus attend l’IO. Si votre processus DB est bloqué pendant les pics, arrêtez de blâmer le load balancer.

Décision : Si un processus domine l’attente IO, analysez son pattern d’écriture (checkpoints, rafales fsync, jobs de sauvegarde). La correction peut se trouver dans le planning applicatif, pas dans ZFS.

Trois mini‑histoires d’entreprise issues du terrain

Mini‑histoire 1 : L’incident causé par une mauvaise hypothèse

Ils ont migré un service transactionnel vers un nouveau cluster de stockage sur ZFS. La revue d’architecture s’est bien passée. « On est sur des SSD maintenant », a dit quelqu’un, et cela a été traité comme un remède universel pour les risques de performance.

La première semaine fut calme. Puis la fin de mois est arrivée. Le service a commencé à afficher des stalls d’écriture de 1–3 secondes. Pas constants—juste assez pour déclencher des retries, amplifier la charge et faire paraître le reste du système instable. Le chef d’incident fit le tour habituel : CPU ok, réseau ok, « ZFS pique ».

L’hypothèse erronée était subtile : ils ont supposé qu’un périphérique NVMe signifiait « écritures sync rapides ». Le pool n’avait pas de SLOG dédié, et la topologie des vdevs était RAIDZ. La charge faisait fréquemment des fsyncs. Pendant les rafales, le pool devait journaliser les sync sur les mêmes périphériques qui traitaient les écritures normales et la parité.

Une fois qu’ils ont regardé total_wait vs disk_wait, c’était évident : disk_wait montait pendant les rafales sync. Ils ont ajouté un SLOG miroir protégé contre la perte d’alimentation et ont déplacé seulement le dataset à fort sync dessus (laissant les autres datasets standards). Les pics de latence n’ont pas disparu ; ils sont retombés dans le plancher du bruit où les graphiques de monitoring vont mourir.

La leçon : « SSD » n’est pas une garantie de performance. C’est un média. L’architecture reste votre problème.

Mini‑histoire 2 : L’optimisation qui a retors

Une autre équipe combattait des pics de latence de lecture aléatoire sur un serveur de fichiers chargé. Quelqu’un a suggéré de désactiver la compression « pour réduire la charge CPU ». Ça semblait raisonnable : moins de CPU, plus de vitesse. Ils ont mis compression=off sur le dataset le plus chaud.

En quelques heures, le p99 a empiré. Pas légèrement—considérablement. Le CPU a baissé un peu, oui, mais la bande passante de lecture disque est montée, tout comme la profondeur de file. Le pool servait désormais plus d’IO physique pour la même charge logique, et ces IO en plus étaient celles qui apparaissent dans la latence tail.

Le vrai problème s’est avéré être les misses ARC déclenchées par un nouveau mix de charge plus une limite mémoire introduite par des paramètres de conteneur. La compression masquait une partie de la pression en rendant les blocs plus petits, augmentant l’« utilité » de l’ARC et réduisant le trafic disque.

Ils ont remis lz4, corrigé la politique mémoire des conteneurs, et posé la règle : « on optimise pour p99, pas pour des métriques CPU esthétiques ». La compression n’était pas le vilain ; la pression mémoire non prise en compte l’était.

Blague n°2 : Désactiver la compression pour réduire la latence, c’est comme enlever la ceinture de sécurité de sa voiture pour améliorer l’accélération—techniquement moins de contraintes, en pratique une mauvaise idée.

Mini‑histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une grande entreprise exécutait des charges mixtes : VMs, partages de fichiers, et quelques bases de données que tout le monde prétendait ne pas être « critiques » jusqu’à ce qu’elles le soient. Ils avaient une politique : fenêtres de scrub hebdomadaires, contrôles SMART mensuels, et investigation immédiate de toute hausse d’erreurs CRC. Ce n’était pas glamour. C’était aussi la raison pour laquelle leur pire incident n’est jamais arrivé.

Un jeudi, la latence a commencé à piquer par courtes rafales : 200ms, puis normal, puis 500ms, puis normal. Les graphiques étaient insupportables. Les stats ZFS ne hurlaient pas « pool en train de mourir ». Aucun disque officiellement failed. Pourtant les utilisateurs remarquaient.

Le on‑call a lancé zpool iostat -v -l et a vu qu’un disque sautait parfois à un énorme disk_wait. SMART montrait une hausse de UDMA_CRC_Error_Count. Ce n’est pas « remplacer le disque », c’est « réparer le chemin ». L’équipe a resserré le disque, remplacé le câble SAS, et tout est rentré dans l’ordre.

Une semaine plus tard, un pic similaire est apparu sur un autre châssis. Même procédure, même correctif, sans drame. La pratique ennuyeuse—traiter les erreurs CRC comme des alertes de première classe—a évité un resilver en mode lent qui aurait écrasé la performance pendant des jours.

La leçon : le meilleur pic de latence est celui que vous n’avez jamais, parce que vous avez cru votre télémétrie.

Erreurs courantes : symptôme → cause racine → correctif

1) « Toutes les 5–10 secondes, les écritures stallent »

Symptôme : vagues rythmées de latence d’écriture ; les applications expirent sur commit ; les graphiques ressemblent à un battement de cœur.

Cause racine : pression de commit TXG. Les données sales s’accumulent plus vite que le pool ne peut les vidanger, ZFS applique une contre‑pression et vous la ressentez comme des stalls périodiques.

Fix : Réduire les sources d’écritures rafales (jobs batch, checkpoints), ajouter de la performance vdev, éviter RAIDZ pour des charges d’écriture aléatoire lourdes, et garder scrub/resilver hors des heures de pointe.

2) « Seules les écritures sync sont lentes ; les async vont bien »

Symptôme : lectures OK ; écritures tamponnées OK ; les applis fsync‑heavy souffrent ; NFS en export sync est terrible.

Cause racine : chemin ZIL lent — soit pas de SLOG, soit un SLOG avec une latence tail horrible, soit un réglage forcé (sync=always).

Fix : Ajouter un SLOG miroir adapté (protections power‑loss), mettre sync=standard sauf si vous avez vraiment besoin de always, et vérifier que l’app n’effectue pas trop de fsync.

3) « Le p99 de lecture aléatoire se dégrade après ajout de locataires »

Symptôme : la moyenne va bien ; le p99 non ; les pics corrèlent avec d’autres jobs.

Cause racine : churn d’éviction ARC et misses de cache dus à la contention mémoire (conteneurs/VMs), plus compétition IO sur les mêmes vdevs.

Fix : Réserver de la RAM, fixer des limites ARC raisonnables, isoler les workloads bruyants sur des pools/vdevs séparés, ou ajouter du média plus rapide pour métadonnées/petits IO.

4) « Les pics sont apparus après activation du chiffrement/compression »

Symptôme : CPU qui monte pendant les pics ; disques pas pleinement utilisés.

Cause racine : pipeline lié au CPU : compression, checksums, ou chiffrement pousse le travail sur le CPU. Si l’ordonnancement CPU patine, les complétions IO paraissent « lentes ».

Fix : Profiler le CPU, pinner correctement les workloads, upgrader le CPU, ou ajuster le niveau de compression. Ne désactivez pas les fonctionnalités d’intégrité à l’aveugle ; prouvez d’abord que le CPU est le goulot.

5) « Tout va bien jusqu’au scrub/resilver, puis les utilisateurs hurlent »

Symptôme : chutes de performance prévisibles pendant la maintenance.

Cause racine : manque de marge. L’IO de maintenance concurrence l’IO de production ; sur HDD RAIDZ, la pénalité est particulièrement forte.

Fix : Planifier les scrubs, ajuster les priorités si la plateforme le permet, et—voici l’impopulaire—acheter assez de disques pour garder de la marge.

6) « Une VM provoque des pics de stockage pour tout le monde »

Symptôme : comportement de voisin bruyant ; rafales d’écritures sync ou petits IO aléatoires dominent.

Cause racine : workload forcé sync (journaux, bases de données) partageant un pool avec des lectures sensibles ; ou mismatch volblocksize d’un zvol causant amplification d’écriture.

Fix : Isoler le stockage de cette VM, tuner les zvols correctement, fournir un SLOG si le sync est requis, ou appliquer du QoS au niveau supérieur si disponible.

7) « Les pics disparaissent après reboot… puis reviennent »

Symptôme : le reboot soigne temporairement les symptômes.

Cause racine : le cache ARC chaud masque des problèmes disque jusqu’à ce que les misses reviennent ; ou fragmentation/snapshot longue durée revient ; ou les retries matériels s’accumulent à nouveau.

Fix : Utilisez la période chaude pour collecter des métriques de base, puis chassez la vraie cause racine : santé disque, changements de charge, taille du cache, gestion de fragmentation.

Une checklist plus stricte : isoler la couche du goulot

Étape 1 : Classifier le pic par type d’IO

  • Pics de lecture : recherchez les misses ARC, latence métadonnées, un disque lent, ou la saturation d’un special vdev.
  • Pics d’écriture : déterminez sync vs async. Pour async : TXG, saturation vdev, math RAIDZ. Pour sync : chemin ZIL/SLOG.
  • Pics métadonnées : beaucoup de créations/suppressions de fichiers, snapshots, petits fichiers, opérations de répertoire. Les special vdevs aident ; HDD RAIDZ déteste cela.

Étape 2 : Décider si vous êtes saturé ou sujet à de la gigue

  • Saturé : %util proche de 100%, longues files, disk_wait élevé. La solution est capacité/performance : plus de vdevs, média plus rapide, moins de jobs concurrents.
  • Gigue : utilisation moyenne modérée mais p99 affreux. Souvent retries firmware, CRC/câblage, comportement SMR, GC sur SSD/NVMe grand public, ou latence tail du journal sync.

Étape 3 : Vérifier que la topologie correspond à la charge

  • Les écritures aléatoires lourdes et sensibles à la latence préfèrent les miroirs (ou mirrors en stries) pour la latence.
  • RAIDZ peut être excellent pour le débit séquentiel et l’efficacité capacité, mais ce n’est pas un spécialiste des écritures aléatoires à faible latence.
  • Les special vdevs peuvent transformer les performances métadonnées, mais ils font désormais partie de l’histoire de survie du pool. Miroirez‑les.

Étape 4 : Faire d’abord des changements réversibles

  • Replanifiez scrubs et sauvegardes.
  • Ajustez des propriétés de dataset comme atime, logbias et primarycache quand c’est justifié.
  • Ce n’est qu’après preuve : ajouter SLOG, ajouter vdevs, migrer la charge, reconstruire le pool pour corriger ashift.

Schémas de pics de latence et leur signification habituelle

Schéma : « Pics courts, un disque est toujours le pire »

C’est le plus simple et le plus souvent ignoré. Si un disque montre systématiquement une latence 10×, le pool fait du travail de groupe avec un collègue qui prend des pauses cigarette pendant les incendies. Remplacez‑le ou réparez le chemin.

Schéma : « Pics seulement lors d’événements fsync‑heavy »

Histoire classique ZIL/SLOG. Apparaît aussi avec NFS en sémantique synchrone, rafales de commit DB, ou systèmes de fichiers invités VM avec barrières agressives. Si vous avez besoin de durabilité, il vous faut du hardware de journalisation durable et à faible latence.

Schéma : « Pics quand la mémoire est serrée »

Réduction ARC + misses augmentent l’IO physique. Si vous exécutez ZFS sur une machine qui héberge aussi un zoo de conteneurs, soyez explicite sur les budgets mémoire. « Ça ira » n’est pas une stratégie mémoire.

Schéma : « Pics après augmentation de la rétention de snapshots »

Les longues chaînes de snapshots ne sont pas mauvaises en soi, mais elles peuvent amplifier le coût des suppressions/réécritures et augmenter la fragmentation. La latence souffre en premier ; le débit tient bien jusqu’à ce qu’il ne tienne plus.

Schéma : « Pics après ajout d’un special vdev »

Le special vdev aide quand il est rapide et non saturé. S’il est sous‑dimensionné, il devient le point chaud. S’il n’est pas miroité (ne le faites pas), il devient le point unique de défaillance du pool.

FAQ

1) Les pics de latence ZFS sont‑ils « normaux » à cause des commits TXG ?

Une certaine périodicité peut être normale sous une charge d’écriture soutenue, mais de gros pics p99 ne sont pas une fonctionnalité. Si les TXGs causent des stalls perceptibles par l’utilisateur, vous poussez trop le pool ou vous luttez contre un goulot sync/journal.

2) Dois‑je mettre sync=disabled pour corriger la latence ?

Seulement si vous êtes prêt à accepter des écritures qui peuvent disparaître en cas de perte d’alimentation ou de crash. Cela peut « résoudre » la latence en supprimant la durabilité. Dans les systèmes réglementés ou transactionnels, ce n’est pas une solution ; c’est un choix de carrière.

3) Ai‑je toujours besoin d’un SLOG ?

Non. Si votre charge émet rarement des écritures sync (ou si vous tolérez la latence), vous pouvez vivre sans. Si vous exécutez des bases de données, du stockage VM, ou du NFS synchrone et que le p99 compte, un bon SLOG fait souvent la différence entre calme et chaos.

4) Pourquoi un disque lent nuit‑il autant au pool ?

Parce que les vdevs font des IO coordonnés. En RAIDZ, la coordination de parité fait que le membre le plus lent fixe le rythme. En miroir, les écritures vont quand même sur les deux côtés. La latence tail est dominée par le plus mauvais participant.

5) Jusqu’à quel remplissage un pool ZFS est‑il « trop plein » ?

Ça dépend de la charge et du type de vdev, mais au‑dessus d’environ 80–85 % vous devriez vous attendre à voir des effets d’allocation et de fragmentation—surtout sur HDD RAIDZ. Si la latence est un objectif, laissez de la marge au sens propre.

6) La compression lz4 est‑elle bonne ou mauvaise pour la latence ?

Souvent bonne. Elle réduit l’IO physique et peut améliorer le p99 si vous êtes limité par l’IO. Elle peut être mauvaise si vous devenez CPU‑bound (machines chargées, chiffrement, cœurs faibles). Mesurez CPU et IO avant de décider.

7) Les snapshots peuvent‑ils provoquer des pics de latence ?

Indirectement, oui. Des snapshots fréquents plus un fort churn peuvent augmenter la fragmentation et le travail des métadonnées. La suppression de gros ensembles de snapshots peut aussi créer une activité d’arrière‑plan lourde que les utilisateurs ressentent.

8) Les special vdevs améliorent‑ils toujours la latence ?

Ils améliorent les performances métadonnées et petits blocs quand ils sont dimensionnés et miroités correctement. Mais ils ajoutent une nouvelle classe de goulot : la saturation du special vdev. Traitez‑les comme du tier‑0 et surveillez‑les.

9) RAIDZ est‑il toujours pire que les miroirs pour la latence ?

Pour les charges d’écriture aléatoire et sensibles à la latence, les miroirs gagnent habituellement. RAIDZ peut être excellent pour les charges séquentielles et l’efficacité capacité. Choisissez selon le pattern IO, pas selon une idéologie.

10) Pourquoi les pics de latence ressemblent parfois à des problèmes réseau ?

Parce que l’application vit un « temps d’attente », et elle ne sait pas s’il s’agit du disque, de l’ordonnancement CPU, de la contention de verrous ou de perte de paquets. C’est pourquoi vous commencez par séparer les couches : vmstat/iostat/zpool iostat, puis le réseau.

Conclusion : étapes suivantes qui réduisent vraiment les pics

Si vous voulez moins de pics de latence ZFS, ne commencez pas par du tuning. Commencez par la classification et les preuves.

  1. Instrumentez et capturez : gardez une capture roulante courte de zpool iostat -l, iostat -x et des stats mémoire pendant les heures de pointe. Les pics non capturés deviennent du folklore.
  2. Corrigez la gigue matérielle évidente : disques outliers, erreurs CRC, chemins instables. Remplacez ou réparez d’abord ; tunez ensuite.
  3. Respectez les sémantiques sync : si la charge a besoin de sync, fournissez un vrai SLOG et validez sa latence tail. Si ce n’est pas nécessaire, ne forcez pas le sync « au cas où ».
  4. Gardez de la marge : marge de capacité et marge de performance. Scrubs, resilvers et sauvegardes ne sont pas optionnels ; planifiez‑les.
  5. Alignez la topologie à la charge : miroirs pour écritures aléatoires sensibles à la latence, RAIDZ pour capacité/débit où c’est adapté, special vdevs pour métadonnées si vous pouvez les exploiter responsablement.
  6. Faites un changement à la fois : et mesurez. Si vous ne pouvez pas dire si ça a aidé, ça n’a pas—du moins pas de façon fiable.

Le but de la checklist n’est pas de vous rendre « bon en ZFS ». C’est de vous rendre rapide pour trouver la seule chose qui cause réellement le pic, avant que le canal d’incident ne développe son propre système météo.

← Précédent
MariaDB vs PostgreSQL : vitesse de restauration — comment obtenir un RTO < 15 minutes
Suivant →
Debian 13 « Could not resolve host » : DNS/proxy/IPv6 — le chemin de diagnostic le plus rapide

Laisser un commentaire