Déséquilibre de vdev ZFS : pourquoi un seul vdev lent ralentit tout le pool

Cet article vous a aidé ?

Vous avez acheté un « stockage rapide ». Le pool donne de bons résultats le premier jour. Puis, un mois plus tard, vos bases de données
commencent à avoir ce comportement où chaque requête semble marcher dans de la colle. Grafana indique une latence. L’équipe applicative accuse le réseau.
L’équipe réseau répond « pas nous ». Vous lancez zpool iostat et voilà : un vdev assis dans un coin, rouge de honte, transpirant, traînant
tout le pool comme s’il montait un canapé trois étages.

ZFS est remarquablement équitable et remarquablement impitoyable. Il utilisera tous les vdev… jusqu’à ce qu’un vdev ne puisse plus suivre.
Alors le pool est effectivement réglé par le participant le plus lent, surtout pour les écritures et les charges sensibles à la latence.
Ce n’est pas une histoire « ZFS c’est nul ». C’est une histoire « la physique est impolie » — plus une poignée de choix d’architecture
que vous pouvez utiliser, abuser ou corriger.

Ce que « déséquilibre de vdev » signifie vraiment (et ce que ça ne signifie pas)

Dans ZFS, un pool est une collection de vdev. Un vdev est l’unité atomique d’allocation de stockage : ZFS stripe
les données à travers les vdev, pas à travers les disques individuels (avec la réserve importante qu’un vdev RAIDZ ou miroir
utilise plusieurs disques en interne).

« Déséquilibre de vdev » désigne le cas où un vdev réalise une part disproportionnée du travail, ou termine son travail beaucoup plus
lentement, de sorte que la latence ou le débit au niveau du pool est contraint. Cela peut être :

  • Déséquilibre de performance : le vdev A a une latence plus élevée / moins d’IOPS que le vdev B sous une charge similaire.
  • Déséquilibre d’allocation : le vdev A est beaucoup plus plein / fragmenté, donc les nouvelles allocations sont plus difficiles et lentes.
  • Déséquilibre de charge : des rôles « spéciaux » (SLOG, special vdev, patterns L2ARC pour métadonnées) canalisent les E/S vers un sous-ensemble.
  • Déséquilibre lié à un mode de défaillance : un périphérique réessaie, remappe, ou meurt silencieusement, et vous payez le prix en latence de pointe.

Ce que ce n’est généralement pas : ZFS qui « choisit des favoris » au hasard. ZFS a des règles. Si un vdev est plus lent, plus rempli,
plus fragmenté, ou présente des erreurs intermittentes, ZFS continuera à soumettre des E/S, et la latence perçue par l’utilisateur devient
la somme de milliers de petits « attends que le lent finisse ».

Blague sèche #1 : Un vdev lent, c’est comme une réunion de statut qui « ne prendra que cinq minutes » — vous y serez toujours à 11h30.

Comment ZFS répartit les E/S entre vdev

Le pool est un stripe à l’échelle des vdev, pas une soupe magique de performance

Le modèle mental de base qui vous garde sain d’esprit : ZFS alloue des blocs aux vdev, et il essaie généralement de maintenir
l’espace libre équilibré (avec un pondération) entre les vdev. Quand vous avez plusieurs vdev de premier niveau, le pool se comporte
comme un stripe au niveau des vdev. Pour de nombreuses charges, cela signifie que le débit évolue avec le nombre de vdev.
Mais cela signifie aussi que le pool hérite du comportement de latence le plus mauvais de tout vdev participant à la charge.

Décisions d’allocation : metaslabs, space maps et préférence pour « le moins pire »

ZFS divise les vdev en metaslabs. Les metaslabs ont des space maps, et ZFS utilise des heuristiques pour choisir où placer
de nouveaux blocs. Il préfère les metaslabs avec plus d’espace libre et de meilleures caractéristiques d’allocation. Au fil du temps,
la fragmentation et le remplissage changent le coût d’allocation.

Deux conséquences importantes :

  • Quand les vdev se remplissent, l’allocation devient plus coûteuse et plus fragmentée. Un vdev utilisé à 80–90 %
    peut devenir sensiblement plus lent qu’un vdev utilisé à 40–60 %, même si les disques sont identiques.
  • « Espace libre équilibré » n’équivaut pas à même performance. ZFS peut maintenir l’espace libre à peu près égal,
    mais il ne peut pas égaliser le comportement physique des périphériques, les bizarreries du firmware, ou les erreurs médias cachées.

Lectures vs écritures : pourquoi on ressent d’abord la douleur sur les écritures

Les lectures ont souvent plus d’« échappatoires » : cache ARC, prélecture, effets de compression, et la possibilité que vos données chaudes
se retrouvent par hasard ou par politique sur le vdev plus rapide. Les écritures ont moins d’options. Quand l’application attend un write sync,
le maillon le plus lent devient toute la chaîne.

Special vdev, SLOG et le problème du « funnel de performance »

Certaines fonctionnalités ZFS routent intentionnellement des E/S spécifiques vers des périphériques dédiés :

  • SLOG (separate log) pour les écritures synchrones (ZIL). Super si c’est rapide et sûr contre les pertes de puissance ; catastrophique si c’est lent ou surchargé.
  • Special vdev pour les métadonnées et (optionnellement) les petits blocs. Génial s’il est correctement provisionné ; un goulot si sous-dimensionné ou plus lent que les vdev principaux.
  • L2ARC pour le cache de lecture. N’alourdit pas directement les écritures, mais peut modifier les schémas de lecture et masquer les problèmes jusqu’à l’effondrement des cache misses.

Si vous concevez un entonnoir, vous en assumez la responsabilité. Mettez un périphérique lent en bas et vous avez construit une machine à latence.

Pourquoi un seul vdev lent pénalise tout le pool

La latence de pointe (tail latency) est la vraie limitation du pool

Les discussions sur les performances de stockage aiment les moyennes parce que les moyennes sont polis. Les systèmes de production vivent en
percentiles parce que les percentiles sont honnêtes. Si un vdev a des pics périodiques de 200–800 ms dus à des réessais de firmware,
à une amplification d’écritures SMR, ou à une file de contrôleur saturée, ces pics se propagent.

ZFS ne fait pas un « attendre tout le monde » synchronisé entre vdev pour chaque bloc du pool. Mais la vue de la latence par votre
application est quand même façonnée par la E/S la plus lente dont elle dépend : commits des transaction groups, flush du journal des writes sync,
mises à jour de métadonnées, blocs indirects, et les petites E/S aléatoires où le parallélisme est limité.

RAIDZ et miroirs : la géométrie interne compte

Un vdev de premier niveau peut être un miroir, un RAIDZ1/2/3, ou un disque unique (à ne pas faire). Si un disque à l’intérieur d’un vdev RAIDZ
ralentit — parce qu’il est en train de lâcher, parce que c’est un SMR, ou parce qu’il est derrière un expander étrange — alors la latence de
tout le vdev RAIDZ peut gonfler. Vous ne pouvez pas « ignorer » le disque lent ; les calculs de parité et les lectures de reconstruction sont des
activités de groupe.

Les miroirs se comportent différemment : les lectures peuvent être servies par l’un ou l’autre membre (ZFS choisit selon des heuristiques),
mais les écritures doivent aller sur les deux. Un seul membre de miroir ralenti augmente la latence d’écriture pour le vdev miroir.

Le scheduler du pool ne peut pas réparer un mauvais vdev

ZFS peut mettre en file les E/S intelligemment. Il peut émettre davantage vers les vdev rapides. Il peut distribuer les allocations.
Il ne peut pas transformer un périphérique lent en périphérique rapide, et il ne peut pas supprimer la physique de l’équation.
Quand la charge implique des écritures synchrones, des dépendances de métadonnées, ou un nombre restreint d’E/S concurrentes, un seul vdev lent devient
le métronome du pool.

Idée paraphrasée (citation fiabilité)

Idée paraphrasée : l’espoir n’est pas une stratégie — Gene Kranz, flight director (largement cité dans la culture ops ; la formulation varie).

En stockage, « espérer que le vdev lent redevienne rapide » n’est pas un plan de remédiation. C’est un événement calendaire en attente.

Faits et contexte historique utiles pour argumenter

  1. ZFS est né chez Sun Microsystems au milieu des années 2000 avec un objectif central : intégrité des données bout en bout via des checksums et le copy-on-write.
  2. Le design « vdev comme unité d’allocation » est délibéré : il simplifie les domaines de défaillance et la modélisation des performances comparé au striping par disque géré à plusieurs niveaux.
  3. Les premières déploiements ZFS misent beaucoup sur RAIDZ pour réduire le write hole de RAID5 et améliorer l’intégrité ; des compromis de performance ont toujours fait partie de l’équation.
  4. OpenZFS moderne a ajouté le « special vdev » pour accélérer métadonnées/petits blocs sur SSD ; cela peut être transformateur — ou devenir un point de rupture unique.
  5. L’ARC de ZFS prédate l’ère actuelle du SSD partout ; beaucoup de plaintes « ZFS est lent » se traduisent en réalité par « ma charge n’est plus dans l’ARC ».
  6. Les disques SMR ont changé le paysage des défaillances : ils peuvent sembler normaux jusqu’à ce que des écritures aléatoires ou des mises à jour soutenues forcent un comportement read-modify-write et des pics de latence.
  7. Secteurs 4K et ashift sont devenus un impôt de performance à long terme : un ashift incorrect est permanent pour ce vdev et peut réduire silencieusement les performances d’écriture.
  8. Les scrubs ZFS sont un choix de conception, pas une tâche accessoire : les scrubs réguliers trouvent les erreurs latentes avant qu’un resilver ne les nécessite.
  9. Timeouts et réessais de périphérique sont l’ennemi caché : même une petite quantité de réessais peut dominer la latence en queue et l’expérience utilisateur.

Mode opératoire de diagnostic rapide (vérifier premier/deuxième/troisième)

Premier : confirmer que c’est un goulot vdev, pas l’application qui ment

  • Exécutez zpool iostat -v avec les colonnes de latence si disponibles sur votre plateforme, et surveillez quel vdev a la pire await ou le temps de service le plus long.
  • Vérifiez si le pool effectue un scrub/resilver. Si oui, arrêtez de deviner : votre base de référence de performance est déjà invalide.
  • Vérifiez le type de charge : écritures sync, petites lectures aléatoires, streaming séquentiel, ou charge lourde en métadonnées. La manifestation du « vdev lent » diffère selon le cas.

Deuxième : isoler si le vdev est lent parce qu’il est occupé, en panne, ou structurellement désavantagé

  • Occupé : forte utilisation, profondeur de queue élevée, débit I/O soutenu élevé.
  • En panne : débit I/O moyen mais énormes pics de latence, erreurs qui augmentent, réinitialisations de lien, timeouts.
  • Structurellement désavantagé : beaucoup plus plein que les autres, special vdev sous-dimensionné, ashift incorrect, mélange SMR/CMR, recordsize trop petit provoquant une famine d’IOPS.

Troisième : décider si vous pouvez corriger en direct ou si une reconstruction/migration est nécessaire

  • Correction en direct : remplacer un périphérique, retirer un log device, ajouter des vdev, ajuster les propriétés des datasets, rééquilibrer en réécrivant les données.
  • Reconstruire/migrer : mauvais type de vdev, ashift incorrect, média mixte qui restera toujours mauvais, special vdev trop petit pour évoluer sans redesign.

Blague sèche #2 : RAIDZ ne se soucie pas de vos sentiments, seulement de votre budget IOPS.

Tâches pratiques : commandes, sorties, décisions (12+)

Tâche 1 : Identifier le vdev lent sous charge réelle

cr0x@server:~$ zpool iostat -v 2 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        18.2T  7.45T   8200  4100   780M  420M
  raidz2-0  9.10T  3.72T   4100  2000   390M  205M
    sda         -      -   1100   520   105M  54.0M
    sdb         -      -   1000   510   95.0M 53.5M
    sdc         -      -    950   500   92.0M 52.0M
    sdd         -      -   1050   520   98.0M 54.0M
    sde         -      -   1000   510   95.0M 52.5M
    sdf         -      -   1000   510   95.0M 53.0M
  raidz2-1  9.10T  3.73T   4100  2100   390M  215M
    sdg         -      -   1050   540   98.0M 55.0M
    sdh         -      -   1000   530   95.0M 54.0M
    sdi         -      -    200   520   18.0M 53.0M
    sdj         -      -   1050   540   98.0M 55.0M
    sdk         -      -   1000   530   95.0M 54.0M
    sdl         -      -   1000   530   95.0M 54.0M

Ce que ça signifie : Le disque sdi contribue à beaucoup moins de lectures que ses pairs. Cela peut vouloir dire qu’il est lent, qu’il génère des erreurs,
ou qu’il subit des réessais si lourds que l’ordonnanceur l’évite pour les lectures.

Décision : Passez immédiatement aux SMART + logs kernel pour sdi, et vérifiez le câblage/chemin du contrôleur. S’il fait partie d’un miroir,
envisagez de remplacer ; s’il est en RAIDZ, attendez-vous à ce que tout le vdev souffre lors des lectures de reconstruction.

Tâche 2 : Vérifier l’état du pool et l’accumulation d’erreurs

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Replace the device or clear the errors.
  scan: scrub repaired 0B in 12:41:20 with 0 errors on Tue Dec 24 03:12:51 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0
            sdd     ONLINE       0     0     0
            sde     ONLINE       0     0     0
            sdf     ONLINE       0     0     0
          raidz2-1  ONLINE       0     0     0
            sdg     ONLINE       0     0     0
            sdh     ONLINE       0     0     0
            sdi     ONLINE       3     0     0
            sdj     ONLINE       0     0     0
            sdk     ONLINE       0     0     0
            sdl     ONLINE       0     0     0

errors: Permanent errors have been detected in the following files:

        /tank/vmstore/vm-104-disk-0

Ce que ça signifie : sdi a des erreurs de lecture. De plus, des erreurs permanentes existent dans un fichier : la pipeline de checksum/réparation n’a pas pu corriger complètement.

Décision : Considérez sdi comme suspect. Remplacez-le, puis restaurez les données affectées à partir des sauvegardes ou des réplicas. Ne « nettoyez et espérez » pas sans comprendre l’impact.

Tâche 3 : Vérifier si une activité de scrub/resilver masque le comportement normal

cr0x@server:~$ zpool status tank
  pool: tank
 state: ONLINE
  scan: resilver in progress since Wed Dec 25 01:10:02 2025
        3.22T scanned at 1.14G/s, 920G issued at 322M/s, 18.0T total
        920G resilvered, 5.00% done, 0:46:10 to go
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
          raidz2-1  ONLINE       0     0     0

Ce que ça signifie : Vous êtes en pleine résilience. Les plaintes de performance pendant un resilver sont attendues ; ce qui compte est de savoir si un vdev est disproportionnellement lent.

Décision : Si votre SLA saigne, envisagez de planifier les resilver/scrub pendant les périodes de faible trafic et assurez-vous que ashift, la classe de périphérique, et les chemins de contrôleur ne créent pas une autoroute à une seule voie.

Tâche 4 : Confirmer si un vdev est beaucoup plus plein que les autres

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME   USED  AVAIL  REFER  MOUNTPOINT
tank  18.2T  7.45T   192K  /tank
cr0x@server:~$ zpool list -v tank
NAME        SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH
tank       25.6T  18.2T  7.45T        -         -    38%    70%  1.00x  ONLINE
  raidz2-0  12.8T  9.10T  3.72T        -         -    31%    70%      -  ONLINE
  raidz2-1  12.8T  9.10T  3.73T        -         -    46%    70%      -  ONLINE

Ce que ça signifie : Les deux vdev ont une allocation similaire, mais la fragmentation diffère : raidz2-1 est plus fragmenté.

Décision : Attendez-vous à un coût d’allocation plus élevé et à une pire latence de pointe sur le vdev le plus fragmenté. Si la fragmentation est élevée et stable, planifiez une stratégie de réécriture/rééquilibrage (send/recv ou migration de dataset).

Tâche 5 : Attraper le motif « un périphérique réessaie » dans les logs kernel

cr0x@server:~$ dmesg -T | egrep -i "ata|scsi|nvme|reset|timeout|error" | tail -n 20
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] tag#1034 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] Sense Key : Medium Error [current]
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] Add. Sense: Unrecovered read error
[Wed Dec 25 02:13:22 2025] blk_update_request: I/O error, dev sdi, sector 7814037096 op 0x0:(READ)
[Wed Dec 25 02:13:25 2025] ata12.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[Wed Dec 25 02:13:26 2025] ata12.00: failed command: READ FPDMA QUEUED
[Wed Dec 25 02:13:27 2025] ata12: hard resetting link

Ce que ça signifie : Réinitialisations matérielles et erreurs de lecture non récupérables créent de longs blocages. Même si ZFS « répare » les lectures, vous payez en latence et en blocages de file d’attente.

Décision : Remplacez le périphérique et inspectez tout le chemin : firmware HBA, expander, backplane, câbles. Si plusieurs disques montrent des resets, suspectez d’abord le chemin.

Tâche 6 : Récupérer l’état SMART/NVMe et chercher les compteurs de « mort silencieuse »

cr0x@server:~$ smartctl -a /dev/sdi | egrep -i "realloc|pending|uncorrect|offline|error|timeout|crc"
  5 Reallocated_Sector_Ct   0x0033   098   098   010    Pre-fail  Always       -       24
197 Current_Pending_Sector  0x0012   100   100   000    Old_age   Always       -       6
198 Offline_Uncorrectable   0x0010   100   100   000    Old_age   Offline      -       6
199 UDMA_CRC_Error_Count    0x003e   200   200   000    Old_age   Always       -       34

Ce que ça signifie : Des secteurs pending/uncorrectable indiquent un problème média. Les erreurs CRC pointent généralement vers des problèmes de câblage/backplane.

Décision : Si les CRC augmentent, réinsérez/remplacez le câble ou le connecteur et surveillez. Si des pending/uncorrectable existent, planifiez le remplacement. N’ouvrez pas de négociation avec l’entropie.

Tâche 7 : Vérifier si les écritures sync sont régulées par un SLOG lent ou manquant

cr0x@server:~$ zpool status 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
          raidz2-1    ONLINE       0     0     0
        logs
          nvme0n1p2   ONLINE       0     0     0

Ce que ça signifie : Il y a un périphérique de log dédié. Si la latence des écritures synchrones est terrible, ce périphérique est suspect — ou simplement saturé.

Décision : Mesurez la latence du vdev de log spécifiquement (iostat, smart, nvme). S’il s’agit d’un NVMe grand public sans protection contre les pertes de puissance, reconsidérez : la sécurité des données et les pics de latence ne sont pas des options facultatives.

Tâche 8 : Identifier le special vdev et vérifier s’il devient le goulot

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

        NAME            STATE     READ WRITE CKSUM
        tank            ONLINE       0     0     0
          raidz2-0      ONLINE       0     0     0
          raidz2-1      ONLINE       0     0     0
        special
          mirror-2      ONLINE       0     0     0
            nvme1n1p1   ONLINE       0     0     0
            nvme2n1p1   ONLINE       0     0     0

Ce que ça signifie : Les métadonnées (et peut-être les petits blocs) résident sur le special vdev. S’il est lent, tout le pool paraît lent — surtout pour les charges riches en métadonnées.

Décision : Vérifiez les propriétés des datasets comme special_small_blocks. Assurez-vous que le special vdev a assez de capacité et une endurance/latence comparable à votre charge.

Tâche 9 : Voir les paramètres des datasets qui peuvent amplifier le déséquilibre de vdev

cr0x@server:~$ zfs get -o name,property,value -s local recordsize,compression,atime,sync,logbias,special_small_blocks tank/vmstore
NAME          PROPERTY              VALUE
tank/vmstore  recordsize            16K
tank/vmstore  compression           lz4
tank/vmstore  atime                 off
tank/vmstore  sync                  standard
tank/vmstore  logbias               latency
tank/vmstore  special_small_blocks  16K

Ce que ça signifie : Un petit recordsize associé à special_small_blocks=16K fait que beaucoup de blocs vont sur le special vdev. C’est acceptable si le special vdev est rapide et spacieux.

Décision : Si le special vdev est presque plein ou a une latence élevée, réduisez special_small_blocks (ou désactivez-le), ou redesign : plus de capacité spéciale, périphériques plus rapides, ou un autre recordsize adapté à la charge.

Tâche 10 : Quantifier la latence du vdev directement avec les stats par périphérique

cr0x@server:~$ iostat -x 2 3
Linux 6.8.0 (server) 	12/25/2025 	_x86_64_	(32 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           9.21    0.00    3.14    7.88    0.00   79.77

Device            r/s     w/s   rkB/s   wkB/s  aqu-sz  await  r_await  w_await  svctm  %util
sda             95.0    52.0  97280   53248     1.2   10.5     9.8     11.7    2.1   31.0
sdi             18.0    50.0  18432   51200    14.8  214.2   390.1     62.3    6.8   97.0
nvme0n1        620.0   410.0  640000  420000    0.9    1.4     1.2      1.7    0.2   18.0

Ce que ça signifie : sdi a une énorme await et est proche de 100 % d’utilisation avec une file profonde. C’est le symptôme classique du vdev lent.

Décision : Si c’est persistant, remplacez/évacuez le disque ou réparez le chemin. Si c’est par à-coups, cherchez des jobs en arrière-plan (scrub, sauvegarde, snapshots) ou un comportement SMR.

Tâche 11 : Vérifier ashift pour trouver les erreurs d’alignement permanentes

cr0x@server:~$ zdb -C tank | egrep -i "vdev_tree|ashift" -n | head -n 30
54:        vdev_tree:
78:            ashift: 12
141:            ashift: 9

Ce que ça signifie : Des valeurs ashift mixtes dans un même pool sont suspectes. Un ashift de 9 (512B) sur des disques 4K-native peut provoquer des pénalités read-modify-write.

Décision : Si vous trouvez un ashift incorrect, vous ne pouvez pas le « régler ». Planifiez un remplacement/migration de vdev. Ne construisez pas de nouveaux pools sans définir explicitement ashift si vous tenez à des performances prévisibles.

Tâche 12 : Détecter une fragmentation sévère et une pathologie d’allocation

cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,health tank
NAME  SIZE   ALLOC  FREE  FRAG  CAP  HEALTH
tank  25.6T  18.2T  7.45T  38%  70%  ONLINE

Ce que ça signifie : La fragmentation n’est pas automatiquement fatale, mais quand elle augmente avec le remplissage du pool, les charges d’écriture aléatoire sont pénalisées.

Décision : Si FRAG est élevé et que les performances souffrent, planifiez un cycle de réécriture (send/recv vers un pool neuf, ou migration de dataset) plutôt que des réglages interminables.

Tâche 13 : Voir si un vdev réalise une part disproportionnée d’E/S sur la durée

cr0x@server:~$ zpool iostat -v -l 5 3
                              operations         bandwidth          total_wait
pool                       read  write       read  write            read  write
-------------------------  ----  -----      -----  -----           -----  -----
tank                       8200  4100       780M   420M            12ms   28ms
  raidz2-0                 4100  2000       390M   205M             8ms   16ms
  raidz2-1                 4100  2100       390M   215M            45ms   82ms
-------------------------  ----  -----      -----  -----           -----  -----

Ce que ça signifie : raidz2-1 a un temps d’attente beaucoup plus élevé que raidz2-0 pour un débit similaire. C’est un déséquilibre au niveau vdev, pas un artefact.

Décision : Creusez dans les périphériques à l’intérieur de raidz2-1. S’ils sont sains, suspectez le remplissage/fragmentation, le chemin du contrôleur, ou des modèles/firmware de disques mixtes.

Tâche 14 : Identifier qui génère les E/S (car « le stockage est lent » n’est pas un processus)

cr0x@server:~$ zpool iostat -v 1
...output...
cr0x@server:~$ iotop -oPa
Total DISK READ:   145.20 M/s | Total DISK WRITE:  81.33 M/s
  PID USER      DISK READ  DISK WRITE  SWAPIN      IO>    COMMAND
23144 root      90.12 M/s   1.23 M/s   0.00 %  22.14 %   /usr/sbin/zfs receive -u tank/vmstore
18201 postgres   8.10 M/s  45.77 M/s   0.00 %  10.31 %   postgres: checkpointer

Ce que ça signifie : Un zfs receive écrit intensément, et Postgres effectue des checkpoints. Cela peut créer des rafales d’écritures sync et un fort churn de métadonnées.

Décision : Si c’est de la réplication planifiée, limitez le débit ou planifiez-la. Si c’est non planifié, trouvez le propriétaire du job. Ensuite, ajustez les datasets (recordsize, comportement sync) de manière appropriée, pas émotionnelle.

Modes de défaillance courants qui créent un déséquilibre de vdev (ce qui arrive en vrai)

1) Médias mixtes ou mélanges de classes de comportement

Mélanger des modèles de HDD qui semblent similaires sur le papier peut quand même créer un déséquilibre parce que le firmware et le comportement du cache diffèrent.
Mélanger CMR et SMR est pire : les SMR peuvent montrer d’énormes pics de latence sous des écritures aléatoires soutenues ou des tâches de maintenance.
Mélanger SATA et SAS derrière différents expanders peut aussi créer un « un vdev est ok, l’autre est hanté ».

Si votre pool a deux vdev RAIDZ et qu’un est construit avec « tout ce qu’on avait », vous n’avez pas un pool ; vous avez une expérience.
La production n’a pas besoin d’expériences.

2) Un seul disque marginal à l’intérieur d’un RAIDZ ou miroir

ZFS gardera le vdev en ligne pendant qu’un disque boîte avec des réessais. C’est bien pour la disponibilité. C’est mauvais pour la latence.
Un disque peut être « assez sain » pour ne pas échouer, tout en étant assez lent pour détruire votre latence de queue. C’est courant avec :

  • Augmentation des secteurs reallocated/pending
  • Erreurs d’interface CRC liées à un câble/backplane instable
  • Throttling thermique dans un châssis dense
  • Bugs firmware qui déclenchent des resets périodiques

3) Special vdev sous-dimensionné ou trop lent

Le special vdev est un multiplicateur de performance quand il est bien conçu et un goulot du pool quand il est mal fait.
Les métadonnées sont petites mais constantes. Si vous placez des petits blocs sur le special et que vous exécutez des images VM avec des blocs 8K–16K,
votre special vdev devient alors le chemin d’écriture pour une grande partie de la charge.

Si le special vdev se remplit, il cesse d’accepter des allocations et vous pouvez obtenir des comportements laids. Plus subtilement : même avant qu’il ne soit plein,
s’il est plus lent que vos vdev principaux (ou simplement saturé), vous verrez le pool « ressentir » la latence du special vdev.

4) Ashift incorrect : dette de performance permanente

Des écritures mal alignées créent des cycles read-modify-write sur le disque. Ce n’est pas une nuisance qu’on peut tunner ; c’est un défaut de conception.
Si un vdev a un ashift incorrect, il peut se comporter comme un vdev lent pour toujours, même lorsque les périphériques sont identiques.

5) Fragmentation + forte occupation du pool

La fragmentation ZFS n’est pas la même chose que la fragmentation d’un système de fichiers traditionnel, mais l’effet est similaire : plus de seeks, plus de métadonnées,
plus de petites E/S. RAIDZ est particulièrement sensible aux petites écritures aléatoires car la parité et le read-modify-write amplifient le travail.
À haute utilisation, la sélection de metaslab devient contrainte, et l’allocateur choisit souvent « la moins mauvaise option ».

6) Travaux en arrière-plan oubliés

Scrubs, resilvers, suppression de snapshots, réceptions de réplication, et compression lourde peuvent dominer les E/S. Un schéma courant :
un vdev est légèrement plus faible, donc le travail en arrière-plan s’y accumule, ce qui le rend plus faible, ce qui fait qu’il se charge encore plus.
Félicitations, vous avez construit une boucle de rétroaction positive.

Trois mini-récits du monde de l’entreprise (anonymisés, plausibles, techniquement exacts)

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

Une entreprise de taille moyenne gérait un cluster de virtualisation soutenu par un pool ZFS : deux vdev RAIDZ2 de niveau supérieur, chacun à six disques.
L’équipe supposait que « même capacité » voulait dire « même performance ». Un vdev avait été construit à partir d’un lot de disques légèrement plus récent
avec une ligne de firmware différente. Les achats ont dit « équivalent ». Ce n’était pas équivalent.

Tout semblait correct dans les tests synthétiques : le débit séquentiel était excellent. Puis est arrivé un lundi — storms de boot VM,
connexions, et une base de données qui ne pardonnait pas les petites lectures aléatoires. La latence a monté, puis est restée élevée.
L’équipe applicative a vu des timeouts. L’équipe stockage ne voyait rien « down ». Le pool était ONLINE, les scrubs passaient, la vie était verte.

La percée est venue en admettant que santé et performance sont des états distincts. zpool iostat -v montrait un vdev
avec des temps d’attente constamment plus élevés pendant les pics de lectures aléatoires. Les iostat -x par disque et les logs kernel montraient des resets de lien intermittents
sur seulement deux disques — assez pour bloquer ce groupe RAIDZ.

La correction n’a pas été un paramètre ZFS astucieux. Elle a été ennuyeuse : remplacer les disques suspects et, plus important, réparer le chemin SAS
qui causait les resets. Ils ont aussi changé leur standard de construction : chaque vdev doit être homogène en modèle/firmware, et chaque chemin HBA/backplane
doit être validé sous charge avant la mise en production.

L’hypothèse incorrecte était subtile : « ZFS équilibrera entre vdev, donc un vdev légèrement étrange ne compte pas. » ZFS a bien équilibré les allocations.
La charge ne se souciait pas de l’équité. Elle se souciait de la latence en queue.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une autre équipe avait un pool servant des répertoires home et des artefacts CI. Les recherches de métadonnées étaient fréquentes, ils ont donc ajouté un special vdev
sur une paire de NVMe grand public. Au début, c’était rapide. Tellement rapide que les gens l’ont surnommé « le mode turbo SSD », une expression qui devrait déclencher une revue des risques.

L’équipe a activé special_small_blocks largement parce que cela améliorait les temps des jobs CI. Puis le mix de datasets a changé :
plus de petits fichiers, plus de couches de conteneurs, plus de petites écritures aléatoires. Le special vdev est devenu à la fois le magasin de métadonnées et le stockage des petits blocs.
L’usure a augmenté. La latence a commencé à vaciller. Personne ne l’a remarqué — ARC et L2ARC cachaient les lectures, et les écritures « généralement » se terminaient vite.

Des mois plus tard, une rafale d’écritures sync pendant les heures de pointe a exposé la faiblesse. Les NVMe grand public ont commencé à se throttler à cause de la chaleur
et des écritures soutenues. Le pool n’est pas tombé. Il a juste donné l’impression d’une panne : les invites de shell se figeaient, les builds échouaient, et tout le monde a accusé le système CI.

Le postmortem a été franc : ils ont optimisé la mauvaise chose. Ils ont traité le special vdev comme un cache (optionnel, best-effort).
Ce n’est pas un cache. C’est le stockage primaire pour ce que vous y placez. La correction a impliqué de remettre les allocations de petits blocs sur les vdev principaux pour la plupart des datasets,
d’améliorer le refroidissement, et de reconstruire le special vdev sur des périphériques de classe entreprise avec protection contre perte de puissance.

Le retour de flamme n’était pas parce que le special vdev est mauvais. Il s’est produit parce qu’ils en ont fait le chemin critique puis l’ont construit comme un jouet.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une équipe de services financiers faisait tourner du NFS soutenu par ZFS pour un mix d’analytique et de partages utilisateurs. Ils avaient un rituel : scrub hebdomadaire, revue mensuelle des tendances SMART,
et règle permanente que tout disque avec une augmentation des CRC ou des pending sectors est remplacé pendant les heures ouvrables. Pas parce qu’il échoue maintenant, mais parce qu’ils n’aiment pas les surprises.

Un jeudi, la latence a commencé à grimper. Pas un pic — juste une montée lente. L’astreinte a vérifié zpool iostat et a vu le temps d’attente d’un vdev augmenter. zpool status était propre.
Pas d’erreurs. Tout ONLINE. Beaucoup d’équipes s’arrêtent là.

Leur pratique « ennuyeuse » a pris le relais : ils ont extrait SMART pour tout le châssis et trouvé un disque avec une petite mais constante augmentation du
UDMA_CRC_Error_Count. Ce n’est pas un cri « remplacez-moi ». Ça murmure « votre câble est capricieux ». Ils ont réinséré le câble, les erreurs ont cessé d’augmenter, et la latence est revenue à la normale sans drame.

Deux jours plus tard, pendant une fenêtre de maintenance planifiée, ils ont remplacé le faisceau de câbles et audité le mapping des lanes du backplane.
Pas d’incident, pas de pertes de données, pas de page à minuit. Le pool n’est jamais devenu DEGRADED. C’est le point. Le meilleur incident est celui qui n’obtient jamais de ticket.

Erreurs fréquentes : symptôme → cause racine → correction

1) « Le débit du pool est correct, mais la latence est horrible »

Symptôme : Gros copies séquentielles rapides ; bases de données et I/O VM bloquent ; pics p99.

Cause racine : Un vdev/périphérique a une latence de pointe élevée (réessais, throttling, comportement SMR), ou le special vdev / SLOG est saturé.

Correction : Identifiez le vdev lent avec zpool iostat -v + iostat -x. Remplacez/réparez le composant lent. Vérifiez le dimensionnement et la classe des périphériques du special vdev.

2) « Un vdev montre un temps d’attente plus élevé alors que les disques sont identiques »

Symptôme : Deux vdev RAIDZ, mêmes modèles de disques, mais l’un est constamment plus lent.

Cause racine : Chemin de contrôleur différent, expander, réglages de queue, ou un disque marginal à l’intérieur du vdev.

Correction : Vérifiez les logs kernel pour resets, vérifiez le câblage/backplane, comparez await/%util par disque. Échangez les disques entre baies si vous avez besoin de preuves.

3) « Le scrub/resilver met une éternité et les performances plongent »

Symptôme : ETA du resilver qui varie énormément ; I/O utilisateur ralentie pendant le scan.

Cause racine : Disque faible ou vdev saturé ; fragmentation élevée ; charge concurrente lourde ; disques SMR.

Correction : Réduisez la charge concurrente, priorisez la fenêtre de réparation, et remplacez les disques lents. Si du SMR est présent, planifiez une migration ; ne discutez pas.

4) « Après avoir ajouté un nouveau vdev, rien n’est devenu plus rapide »

Symptôme : Vous avez ajouté de la capacité/IOPS mais la performance reste contrainte.

Cause racine : Les données existantes restent sur les anciens vdev ; le biais d’allocation ne rééquilibre pas rétroactivement ; le working set n’a pas bougé.

Correction : Rééquilibrez en réécrivant les données (send/recv, rsync vers un nouveau dataset, ou migration de VMs). N’attendez pas de magie d’un « add vdev ».

5) « Charge riche en métadonnées lente, mais disques au repos »

Symptôme : Listes de répertoires, opérations sur petits fichiers, unpacking de conteneurs lent ; %util disque pas élevé.

Cause racine : Special vdev surchargé ou presque plein ; pression ARC causant des ratés metadata constants ; mismatch de recordsize.

Correction : Inspectez l’utilisation du special vdev, les stats ARC, et les propriétés des datasets. Étendez ou redesign du special vdev ; ajustez special_small_blocks et recordsize.

6) « Les performances en écriture aléatoire se sont effondrées après ~80 % d’occupation du pool »

Symptôme : Même charge, mais pire performance au fil du temps ; aucun changement matériel.

Cause racine : Fragmentation + contraintes de l’allocateur + amplification small-write RAIDZ.

Correction : Gardez les pools confortablement en dessous d’une occupation élevée pour les charges d’écriture aléatoire, ou planifiez une réécriture/migration périodique. Les réglages ne désfragmenteront pas un vdev.

Checklists / plan pas à pas

Quand les alertes de latence déclenchent : triage en 15 minutes

  1. Exécutez zpool status. Si scrub/resilver est actif, notez l’incident et ajustez les attentes.
  2. Exécutez zpool iostat -v 2 5. Identifiez quel vdev est lent (déséquilibre wait/débit) et quel disque est étrange.
  3. Exécutez iostat -x 2 3. Confirmez un await élevé/%util sur les périphériques suspects.
  4. Vérifiez dmesg pour resets/timeouts. Si présent, ne débattez pas ; réparez le chemin ou remplacez le disque.
  5. Récupérez SMART/NVMe. Cherchez les pending/uncorrectable et les tendances CRC.
  6. Si des écritures sync sont concernées, inspectez la santé et la charge du SLOG. Si c’est riche en métadonnées, inspectez le special vdev.

Stabiliser d’abord, optimiser ensuite

  1. Retirez le composant défaillant (remplacez le disque, réparez câble/chemin HBA).
  2. Throttlez ou replanifiez les jobs en arrière-plan (réceptions de réplication, scrubs, suppression de snapshots) pendant les pics.
  3. Vérifiez l’occupation du pool et la fragmentation ; planifiez des ajouts de capacité avant d’atteindre la douleur de l’allocateur.
  4. Seulement après stabilité : ajustez les propriétés des datasets pour la charge (recordsize, compression, atime, sync/logbias là où c’est pertinent).

Plan de rééquilibrage (parce qu’ajouter des vdev ne déplace pas les anciens blocs)

  1. Créez un nouveau dataset (ou un nouveau pool) avec les bonnes propriétés.
  2. Utilisez zfs send/zfs receive pour réécrire les données sur la nouvelle disposition d’allocation.
  3. Basculer les consommateurs (points de montage, partages, config de stockage VM).
  4. Détruisez les anciens datasets pour libérer de l’espace et réduire la fragmentation.

Checklist de conception pour prévenir le déséquilibre (ce que j’imposerais dans un standard de construction)

  • Vdev homogènes : même modèle de disque, même famille de firmware, et niveau d’usure approximatif identique.
  • Ashift cohérent (le définir délibérément).
  • Séparer les rôles de performance uniquement avec des périphériques appropriés (PLP pour SLOG, SSD entreprise pour special vdev).
  • Marge de capacité : ne pas faire fonctionner des pools chauds à 85–95 % si vous tenez aux écritures aléatoires.
  • Sanité des chemins de contrôleur : valider expanders/backplanes ; garder le queueing cohérent entre vdev.
  • Hygiène opérationnelle : scrubs réguliers, surveillance des tendances SMART, et responsabilité claire pour les jobs I/O lourds.

FAQ

1) Est-ce qu’un seul disque lent ralentit toujours tout le pool ZFS ?

Pas toujours, mais assez souvent pour s’en prémunir. Si le disque lent est à l’intérieur d’un vdev RAIDZ, il peut augmenter la latence de ce vdev.
Si votre charge dépend de ce vdev (elle le fera), la latence p99 peut bondir. L’ARC peut masquer la douleur de lecture jusqu’à un certain point.

2) Pourquoi ZFS « utilise » quand même le vdev lent ?

Parce que le pool est construit à partir de vdev, et ZFS alloue à travers eux. Il peut biaiser les allocations en fonction de l’espace libre et d’heuristiques,
mais il ne peut pas éviter définitivement un vdev sans le retirer. Si vous voulez que ZFS ne l’utilise pas, il faut redesign : remplacer ou retirer.

3) Si j’ajoute un nouveau vdev rapide, ZFS va-t-il rééquilibrer les données existantes ?

Non. Les blocs existants restent à leur place. Les nouvelles allocations auront tendance à aller vers les vdev avec plus d’espace libre, donc la performance peut s’améliorer
lentement au fur et à mesure que le working set change. Si vous avez besoin d’un rééquilibrage immédiat, réécrivez les données (send/recv ou migration).

4) RAIDZ est-il plus sensible au déséquilibre de vdev que les miroirs ?

En général oui pour les petites écritures aléatoires et le comportement de reconstruction. RAIDZ a un overhead de parité et peut faire du read-modify-write pour des stripes partielles.
Les miroirs peuvent servir les lectures depuis l’un ou l’autre membre, ce qui masque parfois un membre lent sur les lectures, mais les écritures paient toujours le membre le plus lent.

5) Un special vdev peut-il devenir le goulot même s’il est SSD ?

Absolument. SSD n’est pas une garantie ; c’est une classe de périphérique avec une grande variance. Un petit special vdev peut se remplir, et un SSD grand public peut se throttler,
subir des pics de latence, ou s’user plus vite sous le churn de métadonnées/petits blocs. Traitez le special vdev comme du stockage de niveau 0, pas comme un cache.

6) Dois-je désactiver les écritures sync pour « réparer » les performances ?

Seulement si vous pouvez tolérer de perdre des écritures reconnues en cas de perte de puissance ou de crash, et si vous comprenez ce que cela implique pour votre application.
Pour les bases de données et le stockage VM, définir sync=disabled à la légère est une régression de fiabilité déguisée en gain de benchmark.

7) Jusqu’à quel niveau un pool est-il trop plein ?

Ça dépend de la charge, mais si vous tenez à la latence d’écriture aléatoire, commencez à vous inquiéter au-dessus d’environ 70–80 % et planifiez la capacité avant 85 %.
L’allocateur a moins de bons choix quand l’espace libre diminue ; la fragmentation et les frais métadonnées se multiplient.

8) Quelle est la façon la plus rapide de prouver que le problème est matériel, pas un « tuning ZFS » ?

Combinez : zpool iostat -v montrant un vdev avec un wait plus élevé, iostat -x montrant await/%util élevé sur des périphériques spécifiques,
et dmesg/smartctl montrant resets ou compteurs d’erreur. Ce triangle est difficile à contester en réunion.

9) Un ashift incorrect peut-il rendre un vdev plus lent que les autres ?

Oui, et c’est permanent pour ce vdev. Le mauvais alignement peut augmenter l’amplification d’écriture et la latence. Si vous trouvez un vdev avec un ashift erroné,
planifiez un remplacement/migration. Ne perdez pas des semaines à tuner autour d’une erreur de géométrie.

10) Pourquoi le pool paraît-il lent quand un seul dataset est très actif ?

Parce que les vdev sont des ressources partagées et ZFS a du travail global (commits txg, mises à jour de métadonnées, space map updates). Un dataset bruyant peut
saturer un vdev, augmenter les temps d’attente, et déborder sur d’autres charges. Séparez les charges (pools différents) quand les enjeux sont élevés.

Conclusion : prochaines étapes qui font réellement la différence

ZFS ne « ralentit » pas mystérieusement. Il fait exactement ce pour quoi il a été conçu : préserver l’intégrité, allouer à travers les vdev, et continuer
à fonctionner même quand des parties du système boitent. Le prix est que vous ressentez chaque composant lent aux endroits qui comptent : latence d’écriture sync,
churn de métadonnées, et comportement en queue.

Faites ceci ensuite :

  1. Trouvez le vdev lent avec zpool iostat -v et confirmez avec iostat -x.
  2. Vérifiez le chemin : logs kernel + compteurs SMART. Remplacez câbles et disques suspects tôt.
  3. Auditez special vdev et design SLOG. S’ils sont dans le chemin critique, construisez-les comme de la production, pas comme un labo.
  4. Planifiez un rééquilibrage basé sur la réécriture après des extensions. Ajouter des vdev ajoute du potentiel ; réécrire les données le réalise.
  5. Gardez de la marge. Si vous voulez un I/O aléatoire prévisible, arrêtez de considérer un pool à 90 % comme normal.

Si vous ne retenez qu’une chose : le pool est aussi rapide que le vdev le plus lent au moment où votre charge en a besoin. Ne discutez pas avec ça.
Concevez autour, surveillez-le, et remplacez vos maillons les plus faibles avant qu’ils ne se présentent à vos clients.

← Précédent
MariaDB vs PostgreSQL sur un VPS : optimiser le rapport vitesse/coût
Suivant →
Rspamd : configuration minimale pour un premier déploiement qui fonctionne réellement

Laisser un commentaire