ZFS : ajout de disques — le piège « Add VDEV » qui crée un déséquilibre

Cet article vous a aidé ?

L’alerte sonne parce que « le stockage est lent ». Le graphique montre une latence en hausse, mais seulement parfois. L’équipe applicative jure que rien n’a changé.
Vous vous connectez, lancez zpool status, et voilà : un nouveau vdev ajouté la semaine dernière, posé à côté de vdevs plus anciens et plus pleins, comme un nouveau venu
qui a récupéré tous les tickets faciles et a quand même planté la production.

ZFS rend l’ajout de capacité facile. Il rend aussi facile la création d’un agencement de pool qui restera irréversiblement déséquilibré en performance et en risque.
Le piège est simple : zpool add ajoute un vdev au niveau supérieur au pool, mais ZFS ne rééquilibre pas automatiquement les données existantes entre les vdevs.
Ce choix de conception unique est la raison pour laquelle votre « extension rapide » devient l’incident stockage du trimestre suivant.

Le piège « Add VDEV » : ce qui se passe réellement

Lorsque vous lancez zpool add, vous n’« ajoutez pas des disques » à un groupe de redondance existant. Vous ajoutez un tout nouveau vdev de niveau supérieur
au pool. ZFS stripe ensuite les nouvelles écritures entre les vdevs de niveau supérieur selon l’espace disponible et quelques heuristiques, mais il ne déplace pas les anciens blocs.
Les anciens vdevs restent pleins de vieilles données ; le nouveau vdev démarre vide et absorbe beaucoup de nouvelles allocations.

Cela paraît acceptable jusqu’à ce que vous vous souveniez de ce qu’un vdev de niveau supérieur signifie : les IOPS, le débit et la tolérance de panne du pool sont la somme (ou le minimum)
de ses vdevs de niveau supérieur. Ajouter un vdev avec une largeur différente, une classe de disque différente, un ashift différent, ou un profil de santé différent change
le comportement du pool pour le reste de sa vie.

Un pool, plusieurs personnalités

Les pools ZFS ne sont pas « un RAID ». Un pool est une collection de vdevs de niveau supérieur. Chaque vdev de niveau supérieur a sa propre redondance (mirror, raidz, dRAID),
et le pool stripe au travers d’eux. C’est le modèle. C’est puissant. C’est aussi la manière dont les gens construisent par accident un chimère de stockage :
trois vdevs RAIDZ2 larges, puis un simple mirror « juste pour ajouter de la capacité rapidement », puis un vdev SSD « pour les métadonnées », et maintenant le pool
se comporte comme un comité où tout le monde vote et la personne la plus lente bloque toujours la réunion.

Pourquoi ZFS ne rééquilibre pas par défaut

L’absence d’auto-rééquilibrage n’est pas de la paresse ; c’est de la prudence. Déplacer des blocs dans un pool en production coûte cher, use les disques, peut entraîner des cas limites lors d’une coupure d’alimentation,
et complique les garanties. ZFS conserve volontiers des pointeurs vers l’endroit où les données vivent déjà. Il optimise la correction et la survivabilité, pas « rendre joli ».

La conséquence opérationnelle est directe : si vous ajoutez un vdev puis vous vous demandez pourquoi un vdev fait tout le travail, la réponse est « parce qu’il est vide et que vous écrivez des données nouvelles ».
Si vous vous demandez pourquoi les lectures frappent toujours les anciens vdevs, c’est parce que les anciennes données y restent. ZFS n’est pas mystérieux.
Il est littéral.

Faits et contexte qui expliquent le comportement

  • ZFS a commencé chez Sun au début des années 2000, conçu pour l’intégrité des données de bout en bout avec des checksums sur chaque bloc, pas seulement pour du « RAID rapide ».
  • Les pools étaient une rupture : au lieu de tailler des LUNs dans des groupes RAID fixes, on agrégeait des vdevs et on allouait dynamiquement.
  • Copy-on-write est le mécanisme central : ZFS ne réécrit jamais les blocs en place ; il écrit de nouveaux blocs et bascule des pointeurs. Excellent pour les snapshots, compliqué pour le « rééquilibrage ».
  • Les vdevs de niveau supérieur sont l’unité de défaillance : perdre un vdev de niveau supérieur, c’est perdre le pool. C’est pourquoi un vdev simple-disque est une bombe à retardement.
  • RAIDZ n’est pas RAID5/6 dans les détails d’implémentation ; c’est à bande variable avec parité, interagissant avec recordsize et schémas d’allocation d’une façon qui surprend les habitués du RAID matériel.
  • « Ashift » est définitif par vdev : choisir un mauvais alignement de taille de secteur peut verrouiller une amplification d’écriture pour la durée de vie de ce vdev.
  • Les vdevs spéciaux (métadonnées/petits blocs) rendent les pools hybrides plus pratiques, mais ont aussi introduit un nouveau composant qui peut rendre le pool inutilisable à la moindre défaillance, à moins d’être en miroir.
  • L2ARC n’a jamais été un cache d’écriture : c’est un cache de lecture et il se réinitialise au redémarrage à moins qu’un L2ARC persistant soit activé et supporté. Les gens l’utilisent encore comme de la RAM magique.
  • Le comportement de resilver diffère selon le type de vdev : les mirrors resilverisent les espaces utilisés ; RAIDZ est plus lourd et touche davantage la géométrie du vdev.

Pourquoi le déséquilibre nuit : performance, résilience et coûts

Performance : le pool est aussi lisse que son vdev le plus lent

Dans un pool équilibré, vos IOPS et votre débit augmentent en ajoutant des vdevs de niveau supérieur de capacité similaire. Dans un pool déséquilibré, vous obtenez des bizarreries :
des pics de bonne performance, suivis de pics de latence quand un vdev est saturé tandis que d’autres sont sous-utilisés.

Voici le schéma classique : vous ajoutez un nouveau vdev, les nouvelles écritures vont majoritairement là, et votre monitoring a l’air parfait. Puis la charge bascule vers des lectures de données plus anciennes
(restauration de sauvegardes, jobs analytiques touchant des partitions historiques, ou une flotte de VM qui boot depuis d’anciennes images). Soudain, les anciens vdevs deviennent des points chauds de lecture,
et le nouveau vdev reste inactif.

Résilience : mixer les niveaux de redondance, c’est acheter du risque avec le CAPEX

La tolérance aux pannes d’un pool n’est pas la « redondance moyenne ». C’est la redondance de chaque vdev de niveau supérieur, et la perte de n’importe quel vdev de niveau supérieur tue le pool.
Ajouter un mirror simple à côté de plusieurs vdevs RAIDZ2, c’est introduire un maillon faible : un mirror à deux disques survit à un disque, tandis que vos RAIDZ2 en survivent à deux. Vous avez maintenant des domaines de panne inégaux.

Ajouter un vdev à disque unique « temporairement », et félicitations : vous venez de créer un pool à une panne de disque de la perte totale.
Le mot « temporaire » a une longue demi-vie dans l’infrastructure.

Coût : vous payez deux fois — d’abord pour les disques, ensuite pour les conséquences

Les pools déséquilibrés coûtent cher de manière ennuyeuse : plus de temps d’astreinte, plus d’escalades, plus de « pourquoi cet hôte est-il plus lent » en debug, plus de mises à niveau prématurées.
Et si vous devez « réparer » la topologie, la solution est souvent disruptive : migrer des données, reconstruire des pools, ou réécrire des blocs de façon contrôlée pendant des semaines.

Blague n°1 : Ajouter un vdev hétérogène à un pool ZFS, c’est comme mettre une roue de secours sur une voiture de course — oui, ça roule, et oui, tout le monde l’entend.

Mode opératoire de diagnostic rapide (vérifications 1/2/3)

Quand quelqu’un dit « ZFS est devenu lent après qu’on a ajouté des disques », ne commencez pas par tuner recordsize. Commencez par prouver si le pool est déséquilibré et où le temps est passé.

Première vérification : un vdev de niveau supérieur fait-il tout le travail ?

  • Vérifiez l’I/O et la latence par vdev avec zpool iostat -v.
  • Recherchez un vdev avec une busy/await constamment supérieure aux autres.
  • Si vous voyez cela, arrêtez. Vous ne déboguez pas une « performance ZFS ». Vous déboguez la « topologie et l’allocation ».

Deuxième vérification : est-ce lié aux lectures, écritures ou aux écritures synchrones ?

  • Mélange lecture/écriture : zpool iostat -v 1 et arcstat (si disponible) pour voir le taux de hits ARC et la pression de lecture.
  • Écritures synchrones : vérifiez zfs get sync et s’il existe un SLOG et s’il est sain.
  • Si les pics de latence correspondent à des rafales d’écritures sync, vous regardez un problème de ZIL/SLOG ou de latence d’écriture sous-jacente.

Troisième vérification : êtes-vous réellement bloqué au niveau du dispositif ?

  • Vérifiez les stats du noyau : iostat -x et compteurs d’erreurs smartctl.
  • Confirmez ashift et tailles de secteur. Un nouveau vdev avec une taille de secteur physique différente peut se comporter différemment sous charge.
  • Recherchez la malice silencieuse : un lien de contrôleur en downshift, un disque en mode SATA 1.5G, ou NCQ désactivé.

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

Ci-dessous des tâches réelles à exécuter sur un hôte Linux OpenZFS typique. Chacune indique ce que la sortie signifie et quelle décision en tirer.
Utilisez-les comme checklist quand vous manquez de sommeil et que votre fenêtre de changement se referme.

Tâche 1 : Afficher la topologie du pool et repérer immédiatement le « nouveau vdev »

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 03:12:44 with 0 errors on Tue Dec 10 02:40: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
            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       0     0     0
            sdj                     ONLINE       0     0     0
            sdk                     ONLINE       0     0     0
            sdl                     ONLINE       0     0     0
          mirror-2                  ONLINE       0     0     0
            nvme0n1p2               ONLINE       0     0     0
            nvme1n1p2               ONLINE       0     0     0
errors: No known data errors

Signification : Ce pool a deux vdevs RAIDZ2 puis un mirror. Ce mirror est d’une classe différente (NVMe) et a un profil de redondance différent.

Décision : Traitez ceci comme un pool hétérogène. Attendez-vous à un biais d’allocation et à des « modes » de performance. Si ce mirror a été ajouté pour la capacité, planifiez une migration
ou une approche de rééquilibrage délibérée plutôt que d’empiler des rustines.

Tâche 2 : Identifier quel vdev est chaud (IOPS et bande passante)

cr0x@server:~$ sudo zpool iostat -v tank 1 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        82.1T  21.9T  3.21K  1.05K   410M   198M
  raidz2-0                  41.0T  3.7T   2.80K   190    360M    31M
    sda                         -      -    470    32     61M   5.2M
    sdb                         -      -    458    30     59M   5.1M
    sdc                         -      -    472    31     61M   5.1M
    sdd                         -      -    469    33     60M   5.3M
    sde                         -      -    467    31     60M   5.2M
    sdf                         -      -    464    33     59M   5.2M
  raidz2-1                  40.9T  3.8T     380   175     49M    29M
    sdg                         -      -     64    29    8.1M   4.8M
    sdh                         -      -     63    30    8.0M   4.9M
    sdi                         -      -     62    28    8.0M   4.7M
    sdj                         -      -     64    29    8.2M   4.8M
    sdk                         -      -     63    29    8.0M   4.8M
    sdl                         -      -     64    30    8.1M   4.9M
  mirror-2                    250G   850G    30    690    1.2M   138M
    nvme0n1p2                   -      -     15   345   0.6M    69M
    nvme1n1p2                   -      -     15   345   0.6M    69M
--------------------------  -----  -----  -----  -----  -----  -----

Signification : Les lectures sont dominées par raidz2-0. Les écritures sont dominées par le mirror NVMe. C’est le comportement classique « le nouveau vdev absorbe les écritures »
et « les anciens vdevs servent les lectures ».

Décision : Si vos plaintes de latence sont liées aux lectures, ajouter plus de vdevs orientés écriture ne résoudra pas le problème. Il faut déplacer les données chaudes,
ajouter d’autres vdevs RAIDZ similaires, ou reconsidérer la conception du pool.

Tâche 3 : Confirmer le biais d’allocation et son degré

cr0x@server:~$ sudo zpool list -v tank
NAME         SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank        104T  82.1T  21.9T        -         -    28%    78%  1.00x  ONLINE  -
  raidz2-0  45.5T  41.0T  3.7T        -         -    34%    91%      -  ONLINE
  raidz2-1  45.5T  40.9T  3.8T        -         -    31%    90%      -  ONLINE
  mirror-2  1.09T   250G   850G       -         -    2%     22%      -  ONLINE

Signification : Deux vdevs principaux sont ~90% pleins, le nouveau mirror est ~22% utilisé. Ce n’est pas une « capacité équilibrée », donc le flux de travail ne sera pas équilibré
à moins que votre charge ne génère magiquement que des écritures nouvelles.

Décision : N’ajoutez pas de petits vdevs en espérant que ZFS « étalera ». Décidez si vous allez ajouter d’autres vdevs de même classe/largeur
ou migrer vers un nouveau pool avec une topologie propre.

Tâche 4 : Vérifier ashift et détecter le problème « nouveau vdev différent »

cr0x@server:~$ sudo zdb -C tank | sed -n '1,120p'
MOS Configuration:
        version: 5000
        name: 'tank'
        state: 0
        txg: 1293387
        pool_guid: 14772854026870511222
        vdev_children: 3
        vdev_tree:
            type: 'root'
            id: 0
            guid: 14772854026870511222
            children[0]:
                type: 'raidz'
                ashift: 12
                nparity: 2
                children[0]: type: 'disk' path: '/dev/sda'
                ...
            children[2]:
                type: 'mirror'
                ashift: 13
                children[0]: type: 'disk' path: '/dev/nvme0n1p2'
                children[1]: type: 'disk' path: '/dev/nvme1n1p2'

Signification : Les vdevs RAIDZ ont ashift=12 (4K). Le mirror a ashift=13 (8K). Ce n’est pas automatiquement erroné, mais c’est une différence comportementale permanente.

Décision : Si vous observez des mismatches d’ashift accidentels dus à une détection erronée de secteurs ou à des types d’appareils mélangés, arrêtez les « correctifs » incrémentaux.
Planifiez une reconstruction avec l’ashift correct plutôt que d’empiler plus d’incohérence.

Tâche 5 : Vérifier les propriétés des datasets qui influent sur la latence (sync, recordsize, compression)

cr0x@server:~$ sudo zfs get -r compression,recordsize,sync tank/vmstore
NAME         PROPERTY     VALUE     SOURCE
tank/vmstore compression  lz4       local
tank/vmstore recordsize   16K       local
tank/vmstore sync         standard  default

Signification : Paramètres VM raisonnables : compression lz4 et recordsize 16K. Sync est standard, donc les écritures synchrones sont honorées.

Décision : Si vous observez une latence sur les écritures synchrones et que vous n’avez pas de SLOG, envisagez d’ajouter un SLOG en miroir sur des périphériques sûrs en cas de coupure.
Ne « corrigez » pas la latence sync en mettant sync=disabled à moins d’accepter explicitement d’expliquer une perte de données dans le postmortem.

Tâche 6 : Vérifier s’il existe un SLOG et s’il constitue un point de douleur unique

cr0x@server:~$ sudo 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
          mirror-2                  ONLINE       0     0     0
        logs
          mirror-3                  ONLINE       0     0     0
            nvme2n1p1               ONLINE       0     0     0
            nvme3n1p1               ONLINE       0     0     0

Signification : Il y a un périphérique de log en miroir. Bien : pas de SLOG mono-disque. De plus, il est séparé du mirror de niveau supérieur.

Décision : Si les logs apparaissent comme un disque unique, corrigez cela avant toute autre action. Un SLOG unique est une panne en attente,
et un SLOG lent est une usine à latence pour les charges sync-intensives.

Tâche 7 : Mesurer la latence réelle et la mise en file au niveau OS

cr0x@server:~$ iostat -x 1 3
Linux 6.8.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             78.0    5.0    62.1     4.1     173.2     9.80   110.2    120.3     18.1   2.8   23.1
sdg             12.0    4.0     9.5     3.2     194.0     0.90    22.4     24.1     17.3   2.4    3.8
nvme0n1          1.0  420.0     0.2   132.0      64.0     1.10     2.6      1.9      2.6   0.1    4.2

Signification : sda a un await élevé et une profondeur de file comparée aux autres disques. Cela signifie généralement que le vdev auquel il appartient est saturé.

Décision : Confirmez que cela correspond à zpool iostat -v. Si oui, vous avez un vdev chaud.
Si non, vous pourriez avoir des problèmes de contrôleur ou de chemin spécifiques à ce disque.

Tâche 8 : Vérifier la pression ARC et si les lectures échappent au cache

cr0x@server:~$ sudo arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  size     c
12:01:11  3200  1200     37   800   25   350   11    50    2  118G  128G
12:01:12  3400  1500     44   980   29   420   12    60    2  118G  128G
12:01:13  3350  1480     44   950   28   430   13    60    2  118G  128G

Signification : Le taux de misses du cache est d’environ 40%+ sous charge. Cela peut transformer votre histoire « nouveau vdev rapide » en « les lectures sur anciens vdevs nous tuent »,
car l’ARC ne vous protège pas.

Décision : Si les misses de lecture corrèlent avec la latence, envisagez d’ajouter de la RAM (souvent l’amélioration IOPS la plus rentable),
ou séparez les datasets chauds sur des vdevs plus rapides et correctement redondants au lieu de tout mélanger.

Tâche 9 : Inspecter la fragmentation et reconnaître la falaise « RAIDZ presque plein »

cr0x@server:~$ sudo zpool get -H -o property,value fragmentation tank
fragmentation	28%

Signification : La fragmentation est non négligeable. En RAIDZ, une forte utilisation combinée à la fragmentation peut amplifier le coût des écritures et la variabilité de latence.

Décision : Si vos vdevs RAIDZ sont à 85–90% et que la frag augmente, arrêtez de vouloir « tuner ». Ajoutez des vdevs équivalents ou migrez.
La physique de l’allocation gagnera toujours.

Tâche 10 : Voir si un dataset est le tyran (et le déplacer si nécessaire)

cr0x@server:~$ sudo zfs list -o name,used,available,refer,compressratio -r tank | head -n 12
NAME                 USED  AVAIL  REFER  RATIO
tank                82.1T  21.9T   128K  1.22x
tank/vmstore        42.8T  21.9T  42.8T  1.05x
tank/backups        25.6T  21.9T  24.1T  1.48x
tank/analytics      11.9T  21.9T  10.7T  1.31x
tank/home           1.8T   21.9T   1.8T  1.63x

Signification : VMstore domine l’espace. Si la charge chaude se trouve là, elle domine aussi l’I/O.

Décision : Envisagez de déplacer tank/vmstore vers un nouveau pool correctement conçu et laisser les datasets plus froids derrière.
Une coupure chirurgicale vaut mieux qu’un héroïque « rééquilibrage de tout ».

Tâche 11 : Vérifier les erreurs silencieuses de périphérique avant d’accuser l’allocation

cr0x@server:~$ sudo smartctl -a /dev/sda | egrep "Reallocated_Sector_Ct|Current_Pending_Sector|Offline_Uncorrectable|UDMA_CRC_Error_Count"
Reallocated_Sector_Ct     0
Current_Pending_Sector    0
Offline_Uncorrectable     0
UDMA_CRC_Error_Count      27

Signification : Les erreurs CRC suggèrent des problèmes de câblage/backplane/contrôleur, pas un média mourant. Cela peut se présenter comme « un vdev est lent ».

Décision : Réparez le chemin physique et corrigez la tendance d’erreurs (remplacez le câble, remettez en place, changez de baie) avant de redessiner le pool.

Tâche 12 : Confirmer que le « nouveau vdev » est réellement utilisé pour les nouvelles allocations

cr0x@server:~$ sudo zpool iostat -v tank 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        82.1T  21.9T   980   2.20K   210M   420M
  raidz2-0                  41.0T  3.7T    820    180    180M    40M
  raidz2-1                  40.9T  3.8T    150    160     28M    36M
  mirror-2                    250G   850G    10   1.86K   2.0M   344M
--------------------------  -----  -----  -----  -----  -----  -----

Signification : Les écritures vont principalement vers le vdev mirror. C’est attendu quand il est plus vide et plus rapide.

Décision : Si ce mirror n’est pas censé être l’évier principal d’écritures (pour des raisons de coût, d’endurance ou de politique),
vous devez redessiner, pas « espérer que ça s’équilibre ».

Tâche 13 : Prouvez que vous ne pouvez pas retirer le vdev de niveau supérieur plus tard (la partie irréversible)

cr0x@server:~$ sudo zpool remove tank mirror-2
cannot remove mirror-2: operation not supported on this pool

Signification : La suppression d’un vdev de niveau supérieur peut ne pas être supportée selon votre version d’OpenZFS et les flags de features du pool — et même lorsqu’elle est supportée,
elle est contraignante et peut prendre du temps.

Décision : Traitez zpool add comme permanent sauf si vous avez validé le support de suppression de vdev dans votre environnement
et que vous pouvez tolérer le temps et le risque.

Tâche 14 : Valider la configuration de vdev spécial (car le perdre peut perdre le pool)

cr0x@server:~$ sudo 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-4                  ONLINE       0     0     0
            nvme4n1p1               ONLINE       0     0     0
            nvme5n1p1               ONLINE       0     0     0

Signification : Le vdev special est en miroir. Bien. S’il avait été un seul périphérique et qu’il mourait, vous pourriez perdre les métadonnées/petits blocs et perdre effectivement le pool.

Décision : Ne jamais exécuter un vdev spécial en production sur un seul périphérique. Mettez-le en miroir, surveillez-le, et dimensionnez-le avec de la marge.

Trois mini-récits d’entreprise du terrain

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

Une entreprise SaaS de taille moyenne avait un pool ZFS soutenant un cluster de virtualisation. Ils avaient deux vdevs RAIDZ2 d’HDD identiques. La croissance était régulière.
Puis un nouveau client est arrivé et le stockage a bondi. Quelqu’un a posé la question évidente : « Peut-on juste ajouter des disques ? »

L’ingénieur de garde a fait ce que beaucoup d’entre nous font à 2 h du matin : il a ajouté un nouveau vdev mirror en utilisant deux disques de rechange, parce que c’était rapide et que la capacité était urgente.
Il a supposé que le pool « se rééquilibrerait », ou au moins « répartirait les I/O » au fil du temps. Le pool est resté en ligne, les graphiques se sont améliorés, tout le monde est retourné dormir.

Deux semaines plus tard, l’équipe plateforme a déployé une nouvelle image VM et la flotte a redémarré. Les boot storms sont un festival de lectures aléatoires petites.
Les lectures ont frappé les anciennes données sur les RAIDZ presque pleins. La latence a grimpé. Le nouveau mirror avait de l’espace libre et de la vitesse, mais cela n’a pas aidé car il contenait surtout des blocs nouveaux.

L’incident n’était pas un mystère ; c’était une dette topologique qui se payait avec intérêt. Leur correctif n’était pas un tuning astucieux. Ils ont migré les datasets VM les plus sollicités vers un nouveau pool
construit à partir de mirrors (adaptés à la charge), puis ont reconverti l’ancien pool pour des données plus froides. La leçon douloureuse : ZFS ne vous protège pas de vos propres hypothèses.

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

Une équipe analytics d’entreprise voulait des requêtes plus rapides. Ils avaient un pool ZFS de vdevs RAIDZ2 HDD. Une proposition d’optimisation bien intentionnée est arrivée :
« Ajoutez quelques NVMe en mirror comme vdev, et ZFS va répartir dessus. Boom : plus rapide. »

Ils ont ajouté le mirror NVMe en vdev de niveau supérieur. Les nouvelles écritures (y compris des données temporaires de spill de requête) ont atterri de façon disproportionnée sur NVMe. Au début, c’était fantastique.
Mais les NVMe étaient de gamme grand-public et pas sûrs en cas de perte de puissance. Pire : ils étaient maintenant sur le chemin d’écriture chaud pour une charge qui faisait beaucoup d’écritures synchrones
à cause d’un comportement applicatif qu’ils ne maîtrisaient pas complètement.

Quelques mois après, un NVMe a commencé à produire des erreurs média. Le mirror les a protégés d’une perte immédiate de données, mais la performance a fortement chuté pendant la gestion des erreurs
et l’activité de resilver. L’impact business était « les requêtes prennent parfois 10x plus de temps », ce qui est la façon dont les pannes analytiques se manifestent : pas indisponible, mais inutilisable.

Le retour de bâton était subtil : ils n’avaient pas seulement « ajouté de la performance ». Ils avaient changé l’allocation, les caractéristiques de défaillance, et le profil opérationnel du pool entier.
Leur solution finale fut banale : déplacer le scratch analytics vers un pool NVMe distinct (en mirrors), garder le pool HDD pour les données durables, et expliciter la sémantique sync.

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

Une société financière utilisait ZFS pour une archive documentaire et une ferme de VM. Leur responsable stockage était allergique aux « solutions rapides » et imposait une politique :
les vdevs de niveau supérieur doivent être identiques en largeur, type et classe de disque ; pas d’exception sans une approbation écrite des risques.

La politique agaçait les gens parce qu’elle rendait les extensions plus lentes. Quand la capacité s’est resserrée, ils n’« ajoutèrent pas n’importe quels disques ».
Ils achetèrent suffisamment de disques pour ajouter un nouveau vdev RAIDZ2 complet correspondant aux existants, et le déployèrent comme un changement planifié avec tests de burn-in.

Des mois plus tard, ils ont eu un problème de firmware de contrôleur qui augmentait la latence sur un chemin SAS. Parce que leurs vdevs étaient cohérents,
leurs métriques racontaient une histoire claire : un chemin était fautif ; la topologie du pool ne brouillait pas le signal. Ils ont isolé le chemin défaillant, basculé proprement,
et planifié une mise à jour de firmware.

Le sauvetage n’était pas héroïque ; c’était de la clarté. Des vdevs homogènes et des changements disciplinés ont fait que le système se comportait de façon prévisible quand le hardware a eu des problèmes,
ce qui est le seul moment où vous découvrez vraiment ce dont votre architecture est faite.

Comment étendre ZFS en toute sécurité (quoi faire à la place)

Règle 1 : Ajoutez des vdevs de niveau supérieur qui correspondent, ou acceptez l’étrangeté permanente

Si vous allez croître un pool en ajoutant des vdevs, ajoutez des vdevs du même type, même largeur et classe de performance similaire. Mirrors avec mirrors.
RAIDZ2 avec RAIDZ2 du même nombre de disques. Ashift similaire. Modèles de disques similaires si possible.

Ce n’est pas esthétique. C’est des maths opérationnelles : le pool stripe entre les vdevs, et n’importe quel vdev peut devenir le facteur limitant selon les schémas d’accès.
L’homogénéité rend la planification de performance et capacité raisonnable.

Règle 2 : Si vous avez besoin de types de médias différents, utilisez des pools séparés ou des vdevs spéciaux délibérés

Vous voulez de la performance NVMe et de la capacité HDD ? Vous avez trois schémas raisonnables :

  • Pools séparés : un pool NVMe pour les datasets sensibles à la latence, un pool HDD pour le stockage massif. Simple, prévisible, facile à raisonner.
  • Vdev spécial (en miroir) : pour les métadonnées et petits blocs, pour accélérer les opérations de répertoire et les petits I/O aléatoires tout en gardant les données sur HDD.
  • SLOG (en miroir, dispositifs PLP) : pour accélérer la latence des écritures synchrones sans changer l’endroit où les données atterrissent finalement.

Ce qu’il faut éviter : « juste ajouter un vdev rapide » en espérant que ZFS en fera un système de tiering. Il ne le fera pas. Il en fera un puits d’allocation.

Règle 3 : Envisagez de reconstruire plutôt que de rafistoler quand la topologie est déjà compromise

Parfois la bonne réponse est : construire un nouveau pool avec la topologie souhaitée, puis migrer les datasets. Oui, c’est du travail. C’est aussi un travail fini.
Vivre avec un pool compromis, c’est du travail infini.

Qu’en est-il du « rééquilibrage » ?

ZFS n’a pas une commande en ligne unique pour rééquilibrer qui redistribue les blocs existants entre vdevs comme le font certains systèmes distribués.
Si vous voulez que les données bougent, vous devez généralement les réécrire.

Approches pratiques :

  • Send/receive de dataset vers un nouveau pool (meilleur quand vous pouvez provisionner un nouveau pool).
  • Réécriture au niveau dataset en place via réplication vers un dataset temporaire puis retour (fonctionne, mais lourd et risqué opérationnellement).
  • Migrations sélectives des datasets chauds vers un nouveau pool, en laissant les données froides où elles sont.

Blague n°2 : ZFS ne « rééquilibre » pas votre pool ; il « préserve l’histoire ». Comme votre département d’audit, il se souvient de tout et ne bouge rien sans paperasse.

Listes de vérification / plan pas à pas

Pas à pas : Avant d’exécuter zpool add en production

  1. Écrivez l’objectif : capacité, IOPS, débit ou latence ? « Plus d’espace » n’est pas un plan de performance.
  2. Confirmez la géométrie des vdevs actuels : mirror vs raidz, nombre de disques, ashift, classes de périphériques.
  3. Décidez si vous pouvez garder les vdevs homogènes : sinon, décidez si vous acceptez l’hétérogénéité permanente.
  4. Vérifiez l’espace libre et la fragmentation : si vous êtes déjà en haute capacité et fragmenté, attendez-vous à un comportement pire sous écriture.
  5. Validez la santé du contrôleur et des chemins : n’ajoutez pas de complexité sur du matériel instable.
  6. Planifiez le rollback : supposez que vous ne pouvez pas supprimer le vdev plus tard ; planifiez comment migrer si cela tourne mal.
  7. Validez et burn-in des disques : lancez des tests SMART longs, vérifiez les firmwares, confirmez les tailles de secteur.

Pas à pas : Schémas d’extension sûrs

  1. Besoin de plus de capacité sur un pool RAIDZ existant : ajoutez un nouveau vdev RAIDZ correspondant en largeur et parité.
  2. Besoin de plus d’IOPS pour des charges VM aléatoires : ajoutez des vdevs mirror (plusieurs mirrors augmentent bien les IOPS).
  3. Besoin d’une latence d’écriture sync plus rapide : ajoutez un SLOG en miroir sur des dispositifs protégés contre la perte de puissance ; n’ajoutez pas un vdev rapide aléatoire.
  4. Besoin d’accélération métadonnées/petits blocs : ajoutez un vdev special en miroir ; définissez special_small_blocks seulement avec un modèle de dimensionnement et de surveillance.
  5. Besoin de tiers rapide et lent : construisez deux pools et placez les datasets explicitement.

Pas à pas : Si vous êtes déjà tombé dans le piège

  1. Quantifiez le déséquilibre : pourcentage d’alloc par vdev, iostat par vdev sous charge réelle.
  2. Identifiez les datasets chauds : quels datasets dominent l’I/O et les plaintes de latence.
  3. Choisissez une architecture cible : vdevs homogènes, ou pools séparés par charge de travail.
  4. Planifiez la migration : send/receive avec snapshots incrémentaux, ou déplacer d’abord les datasets chauds.
  5. Planifiez scrubs et resilvers : les expansions et migrations révèlent les disques faibles.

Erreurs courantes : symptôme → cause racine → correction

1) Symptom : « Après avoir ajouté des disques, les lectures sont encore lentes »

Cause racine : Vous avez ajouté un nouveau vdev, mais les anciennes données sont restées sur les anciens vdevs ; la charge de lecture frappe toujours les vdevs anciens et pleins.

Correction : Déplacez les datasets chauds vers un nouveau pool ou réécrivez-les pour que les blocs se réallouent. Si vous devez étendre en place, ajoutez des vdevs assortis pour augmenter le parallélisme de lecture là où les données résident.

2) Symptom : « Les écritures sont devenues rapides, puis des pics de latence aléatoires sont apparus »

Cause racine : Le nouveau vdev absorbe la plupart des écritures ; les anciens vdevs sont presque pleins et fragmentés ; des médias mixtes provoquent des temps de service inégaux.

Correction : Arrêtez de mélanger des classes de vdev de niveau supérieur pour l’allocation générale. Séparez les pools ou utilisez SLOG/vdev spécial pour une accélération ciblée.

3) Symptom : « La performance du pool est incohérente selon l’hôte / l’heure »

Cause racine : Les phases de charge (lecture d’anciennes données vs écriture de nouvelles données) interagissent avec le biais d’allocation. Le pool a des « modes ».

Correction : Mesurez l’I/O par vdev pendant chaque phase de charge. Placez les datasets selon le schéma d’accès, pas selon l’endroit où il y avait de l’espace libre.

4) Symptom : « Le scrub ou le resilver a explosé après l’extension »

Cause racine : vdevs très utilisés + géométrie RAIDZ + disques lents = opérations de maintenance longues. L’extension n’a pas réduit la saturation des anciens vdevs.

Correction : Ajoutez des vdevs correspondants avant d’atteindre des pourcentages de CAP élevés. Gardez de la marge. Remplacez les disques vieillissants de manière proactive. Envisagez des mirrors pour des resilvers plus rapides quand la charge l’exige.

5) Symptom : « On a ajouté un disque unique temporairement et maintenant on a peur de toucher au pool »

Cause racine : Un vdev top-level mono-disque rend le pool à une panne de disque de la perte totale.

Correction : Convertissez immédiatement ce disque unique en redondance en attachant un second disque (mirror), ou migrez les données hors de ce pool.
Ne laissez pas cela pour « plus tard ».

6) Symptom : « Le nouveau vdev est plus rapide mais le pool est globalement plus lent »

Cause racine : Ashift mixte, tailles de secteur ou amplification d’écriture sur un vdev ; de plus, le comportement métadonnées/petits blocs peut se concentrer sur certains périphériques.

Correction : Validez ashift et propriétés des périphériques avant d’ajouter. Si c’est incorrect, reconstruisez avec l’ashift correct ; n’empilez pas.

7) Symptom : « Les écritures synchrones sont catastrophiques, donc quelqu’un propose sync=disabled »

Cause racine : Pas de SLOG ou SLOG lent/peu sûr. Le pool honore la sémantique sync et paie le prix en latence.

Correction : Ajoutez un SLOG en miroir, protégé contre la perte de puissance ; confirmez les besoins applicatifs ; conservez sync=standard pour la durabilité sauf si vous acceptez explicitement la perte de données.

FAQ (questions fréquentes après l’incident)

1) « Ajouter des disques » est-ce la même chose que « ajouter un vdev » dans ZFS ?

En pratique, oui. Vous remplacez soit des disques dans un vdev existant (croissance ou rafraîchissement), soit vous ajoutez un nouveau vdev de niveau supérieur au pool.
zpool add ajoute un vdev de niveau supérieur. Cela change le comportement du pool de façon permanente.

2) ZFS va-t-il rééquilibrer automatiquement les données après l’ajout d’un vdev ?

Non. Les blocs existants restent là où ils sont. Les nouvelles allocations préfèrent souvent les vdevs avec plus d’espace libre, donc les nouveaux vdevs reçoivent souvent la majorité des écritures.

3) Si j’ajoute un vdev plus rapide, est-ce que les lectures deviendront plus rapides ?

Seulement pour les données allouées sur ce vdev (ou en cache dans ARC/L2ARC). Si vos données chaudes résident sur d’anciens vdevs, les lectures continueront d’y frapper.

4) Puis-je « corriger le déséquilibre » sans migrer vers un nouveau pool ?

Parfois partiellement, en réécrivant les données (send/receive vers un dataset temporaire puis retour, ou en déplaçant des datasets).
Mais il n’y a pas de miracle : pour déplacer des blocs, il faut réécrire des blocs, et cela coûte en I/O et en temps.

5) Est-il sûr de mélanger mirrors et RAIDZ dans un même pool ?

Cela peut fonctionner, mais ce n’est rarement judicieux pour une performance prévisible ou des caractéristiques de défaillance cohérentes.
Si vous le faites, faites-le délibérément et surveillez le comportement par vdev. Sinon, séparez les pools.

6) Quel est le mouvement d’expansion ZFS le plus commun qui casse tout par accident ?

Ajouter un petit vdev mirror à un grand pool RAIDZ parce que « nous avons juste besoin d’un peu plus d’espace ». Vous vous retrouvez avec un pool qui alloue de façon disproportionnée au mirror,
change les patterns d’usure, et rend la planification de capacité future pénible.

7) Ajouter plus de vdevs augmente-t-il toujours la performance ?

Ajouter plus de vdevs similaires augmente généralement le débit et les IOPS agrégés. Ajouter des vdevs dissemblables augmente l’imprévisibilité.
De plus, si votre charge est limitée par le CPU, l’ARC, le comportement sync, ou le réseau, ajouter des vdevs n’aidera pas.

8) Comment choisir entre mirrors et RAIDZ pour la croissance ?

Les mirrors scale mieux pour les IOPS aléatoires en lecture/écriture et resilverisent plus vite ; RAIDZ est efficace en capacité mais plus sensible à la saturation et aux schémas d’écriture.
Pour des workloads VM ou bases de données avec beaucoup d’I/O aléatoire, les mirrors se comportent généralement mieux opérationnellement.

9) Quelle citation retenir quand quelqu’un propose une « solution de stockage rapide » ?

Werner Vogels (idée paraphrasée) : « Tout échoue, tout le temps. » Construisez des layouts et des procédures en supposant que la prochaine panne est déjà planifiée.

Conclusion : actions à mener cette semaine

Si vous ne retenez qu’une chose, que ce soit celle-ci : zpool add n’« étend » pas un RAID. Il ajoute un vdev de niveau supérieur et ne rééquilibre pas les anciennes données.
Ce n’est pas un bug. C’est le modèle.

Étapes pratiques :

  1. Inventoriez vos pools : lancez zpool status et notez les types de vdev, largeurs et classes de périphériques. Si c’est un fouillis, admettez-le maintenant.
  2. Mesurez la charge par vdev : capturez zpool iostat -v 1 pendant les pics de charge réels. Trouvez le vdev chaud.
  3. Décidez de l’architecture : vdevs homogènes dans un pool, ou plusieurs pools par workload. Ne continuez pas d’improviser.
  4. Planifiez la sortie : si vous avez déjà ajouté un vdev inadapté, planifiez une migration tant que le système est encore assez sain pour déplacer des données.

La fiabilité du stockage, c’est surtout éviter les idées « ingénieuses ». ZFS vous donne des outils précis. Utilisez-les comme si vous étiez celui qui sera d’astreinte quand ils craqueront.

← Précédent
Timeouts des conteneurs Docker : ajuster les retries correctement (pas infinis)
Suivant →
Pannes causées par un mauvais câble : comment un seul fil paralyse un datacenter

Laisser un commentaire