ZFS redundant_metadata : quand davantage de copies de métadonnées comptent vraiment

Cet article vous a aidé ?

ZFS a l’art de transformer une discussion sur « système de fichiers » en une discussion sur « architecture de stockage ». Ce n’est pas un bug ; c’est l’idée même. ZFS traite vos données comme un graphe de blocs, et les métadonnées sont la carte. Perdre la carte ne signifie pas « fichier manquant », cela signifie perdre la capacité de prouver ce qu’est réellement le fichier. C’est pourquoi redundant_metadata existe : c’est une propriété de dataset qui décide combien de copies de métadonnées ZFS tente de conserver.

Le problème est que « plus de copies » n’est pas automatiquement synonyme de « meilleur ». Des copies supplémentaires de métadonnées peuvent vous sauver d’un type de corruption qui fait regarder des ingénieurs chevronnés zpool status en silence — mais elles peuvent aussi ajouter silencieusement une amplification d’écriture et transformer un pool déjà en manque d’E/S en un désastre de files d’attente. Cet article explique quand redundant_metadata vaut le coût, quand cela ne vaut pas, et comment faire la différence en production sans deviner.

Ce que fait vraiment redundant_metadata

redundant_metadata est une propriété de dataset ZFS qui influence combien de copies de métadonnées ZFS stocke. Les valeurs les plus courantes que vous verrez sont :

  • all : stocker des copies redondantes de toutes les métadonnées (c’est-à-dire « essayer de conserver des copies supplémentaires »).
  • most : stocker des copies redondantes de la plupart des métadonnées.
  • none : ne stocker aucune copie supplémentaire de métadonnées (au-delà de la redondance fournie par la disposition de vos vdev).

Ce n’est pas la même chose que la propriété copies. copies=2 duplique les données et les métadonnées au niveau du dataset, augmentant considérablement l’utilisation d’espace. redundant_metadata cible uniquement les métadonnées, qui sont généralement bien plus petites que les données utilisateur — jusqu’à ce qu’elles ne le soient pas (pensez à des millions de petits fichiers, des snapshots nombreux, ou des charges de travail riches en métadonnées comme maildir, couches d’images de conteneurs, caches de build).

Nuance importante : ZFS a déjà de la redondance au niveau des vdev (mirror, RAIDZ). redundant_metadata concerne des copies supplémentaires en plus de cela. Sur des mirrors, vous avez déjà deux copies ou plus de chaque bloc parce que le vdev entier est dupliqué. Sur RAIDZ, chaque bloc est protégé par une parité, mais il reste un bloc logique par écriture. Des copies supplémentaires de métadonnées peuvent fournir des instances physiques alternatives de ce bloc de métadonnées, ce qui change l’histoire de récupération lorsqu’il y a une corruption silencieuse ou des problèmes au niveau des secteurs que la parité ne peut corriger (par exemple, des erreurs de lecture répétées sur une région spécifique, ou un périphérique qui renvoie des données incorrectes avec le bon chemin de somme de contrôle étant forcé de réessayer).

Version en une phrase : redundant_metadata est un pari que votre plus grand risque est « les métadonnées deviennent illisibles avant que vous ne le remarquiez », et que vous êtes prêt à payer un certain overhead pour vous couvrir.

Blague #1 (brève et pertinente) : Les métadonnées sont comme le DNS : personne ne s’en soucie jusqu’à ce que ça casse, et soudain c’est « le service le plus critique qu’on ait jamais exécuté ».

Qu’est-ce que « métadonnées » ici ?

Les métadonnées ZFS incluent des éléments tels que les pointeurs de blocs, les blocs indirects, les dnodes (métadonnées de fichier), les structures de répertoire, les space maps et d’autres structures sur disque utilisées pour localiser et vérifier vos données. Certaines métadonnées sont au niveau du pool (MOS et alliés), d’autres sont spécifiques au dataset. En pratique, si vous débouchez une situation inquiétante, par « métadonnées » on entend tout ce qui empêche le système de fichiers de traverser jusqu’au contenu de vos fichiers de façon fiable.

Toutes les métadonnées ne se valent pas. Le contenu corrompu d’un fichier peut être une pièce jointe client que vous pouvez restaurer depuis un snapshot. Des métadonnées corrompues peuvent rendre des datasets entiers impossibles à démonter ou provoquer des échecs de traversée qui bloquent les restaurations (ce qui est le vrai cauchemar : vos sauvegardes existent, mais vous ne pouvez pas les énumérer).

Pourquoi les métadonnées sont la partie qu’on ne peut pas perdre

ZFS est basé sur le copy-on-write. À chaque modification d’un bloc, il écrit de nouveaux blocs puis met à jour les pointeurs vers les nouveaux blocs. C’est pourquoi ZFS est si bon pour la cohérence : il n’écrase pas les structures actives en place ; il construit un nouvel arbre puis bascule un pointeur racine à la fin. Ce modèle a des implications :

  • Le churn des métadonnées peut être très élevé même quand les données utilisateur sont « stables ».
  • La « forme » de vos métadonnées affecte les performances (plus d’indirections, plus d’E/S petites et aléatoires).
  • Les métadonnées rendent les snapshots possibles, mais les snapshots préservent aussi les métadonnées historiques, ce qui peut augmenter le nombre de blocs de métadonnées qui doivent rester lisibles.

Opérationnellement, les pannes ZFS tendent à prendre deux formes :

  • Pannes évidentes de périphérique : un disque meurt, SMART alerte, le mirror se dégrade, vous le remplacez, vous resilverez. Ennuyeux mais routinier.
  • Corruption non évidente et illisibilité partielle : tout a l’air normal jusqu’à ce qu’un scrub ou un accès à un bloc spécifique déclenche des erreurs de somme de contrôle ou des erreurs permanentes. Les blocs de métadonnées sont disproportionnellement pénibles ici, car ils peuvent se trouver sur des chemins critiques : montage, listing de répertoires, opérations sur snapshots, send/receive, voire les scrubs.

Des copies supplémentaires de métadonnées ne vous sauveront pas de toutes les catastrophes. Elles ne peuvent pas réparer « oups, nous avons détruit le pool » et elles ne feront pas du RAIDZ un mirror. Mais elles peuvent transformer un incident de corruption de « il nous faut une fenêtre de restauration et beaucoup de caféine » en « le scrub a réparé et nous avons continué ».

Comment ZFS place les copies supplémentaires (et où il ne peut pas)

ZFS a un mécanisme ancien pour les « ditto blocks » (copies supplémentaires de métadonnées). L’intention est simple : si une instance est mauvaise, une autre peut être bonne, et les sommes de contrôle permettent à ZFS de choisir la bonne. Conceptuellement, c’est similaire à avoir plusieurs réplicas, mais à l’intérieur d’un même pool et contrôlé par des règles d’allocateur.

Il y a des contraintes :

  • Tout ne se copie pas de la même façon. Certaines métadonnées sont déjà gérées spécialement ; d’autres peuvent être trop grandes ou trop fréquentes pour être raisonnablement dupliquées.
  • Les copies doivent atterrir quelque part. Si votre pool est petit, fragmenté ou contraint à un ensemble restreint de périphériques, les « copies supplémentaires » peuvent finir par ne pas être aussi indépendantes que vous le pensez. Deux copies sur le même disque défaillant ne comptent pas comme redondance ; elles comptent comme de l’optimisme.
  • Le special vdev change la donne. Si vous utilisez un special vdev pour les métadonnées, alors le placement et la redondance des métadonnées peuvent devenir à la fois meilleurs et pires : meilleurs parce que les métadonnées sont sur des périphériques rapides, pires parce que vous venez de créer une « couche de métadonnées » qui doit être correctement redondante ou vous avez construit un point de défaillance unique avec une latence supérieure.

Aussi : redundant_metadata ne réécrit pas rétroactivement l’intégralité de votre pool. Il influence les nouvelles écritures. Les blocs de métadonnées existants restent généralement tels quels jusqu’à ce qu’ils soient réécrits par l’activité normale, ou jusqu’à ce que vous forciez des réécritures avec des tactiques spécifiques (ce qui peut être risqué et dépendant de la charge).

Mirrors, RAIDZ et le faux sentiment de « nous avons déjà de la redondance »

Sur des mirrors, chaque bloc est dupliqué au niveau du vdev. La redondance des métadonnées est intrinsèquement forte parce que toute lecture peut provenir de l’un ou l’autre côté, et les sommes de contrôle permettent à ZFS de détecter et d’auto-réparer en réécrivant depuis le côté sain. Dans ce monde, redundant_metadata est souvent moins critique pour l’intégrité (même s’il peut encore être pertinent pour les performances à cause du placement et de la distribution des lectures).

Sur RAIDZ, la parité vous protège d’une défaillance de périphérique jusqu’au niveau de parité, et peut corriger certaines erreurs de lecture. Mais la parité n’est pas magique contre tous les modes de défaillance, surtout quand vous faites face à des erreurs de secteurs latentes, des bugs de firmware, ou un périphérique qui renvoie des données erronées de façon inconsistante. Des copies physiques supplémentaires de métadonnées peuvent aider parce qu’elles créent des sources alternatives pour la même information logique.

Blague #2 (brève et pertinente) : La parité RAIDZ, c’est comme une assurance : c’est génial jusqu’à ce que vous découvriez que la franchise est « reconstruire le pool pendant un week-end ».

Quand davantage de copies de métadonnées compte vraiment

Voici les situations où redundant_metadata tend à rapporter, basées sur la façon dont les pannes apparaissent dans des systèmes réels.

1) Charges riches en métadonnées (millions de fichiers, petits fichiers, arborescences profondes)

Si vous exécutez quelque chose qui crée un nombre énorme d’objets de système de fichiers — caches de build CI, couches d’images de conteneurs, miroirs de paquets, spools de mail, magasins d’artefacts, monorepos de code source — vos « métadonnées » ne sont pas une erreur d’arrondi. Elles deviennent un consommateur principal de capacité et de performances. C’est précisément le type d’environnement où la corruption de métadonnées est également particulièrement perturbante : la traversée touche beaucoup de blocs de métadonnées, et un seul bloc de répertoire corrompu peut bloquer l’accès à de larges zones logiques de données.

Des copies supplémentaires sont précieuses parce que votre probabilité de rencontrer un bloc de métadonnées mauvais augmente avec le nombre de blocs de métadonnées que vous possédez et lisez. C’est de la statistique, pas de la superstition.

2) Rétention longue de snapshots ou planifications agressives de snapshots

Les snapshots préservent des versions historiques de métadonnées, pas seulement des données. Lorsque vous conservez de nombreux snapshots, vous conservez d’anciennes métadonnées. Si une partie de ces métadonnées devient illisible, cela peut casser des opérations comme zfs list -t snapshot, zfs destroy (oui, même la suppression peut être bloquée), et zfs send. C’est comme garder des années de reçus dans une boîte à chaussures — ça va, jusqu’au jour où celui dont vous avez besoin a été renversé par du café.

redundant_metadata=all peut réduire la probabilité qu’un bloc de métadonnées donné soit un point de défaillance unique.

3) Pools avec historique d’erreurs de somme de contrôle ou matériel marginal

Nous voulons tous du matériel entreprise. Parfois vous héritez d’un matériel « best effort » avec une histoire d’achat qui commence par « c’était une super affaire ». Si vous avez vu des erreurs de somme de contrôle intermittentes pendant les scrubs, ou si vous avez dû remplacer des disques pour erreurs de lecture plus d’une fois, la redondance des métadonnées peut être un réducteur de risque pragmatique.

Mais soyez honnête : si vous voyez routinièrement des erreurs de somme de contrôle, la première correction est généralement matérielle — disques, câbles, HBA, firmware, alimentation. redundant_metadata n’est pas un substitut à des chemins d’E/S stables ; c’est une ceinture de sécurité, pas un volant.

4) Pools RAIDZ où les IOPS de lecture de métadonnées sont la contrainte

Cela semble paradoxal : « des copies supplémentaires » signifie plus d’écritures, mais cela peut aussi améliorer la résilience en lecture et, dans certains cas, le comportement en lecture sous erreurs. Dans un pool RAIDZ, un seul secteur mauvais peut forcer des lectures de reconstruction coûteuses. Si ZFS peut lire une bonne copie d’un bloc de métadonnées sans reconstruction, cela peut réduire le rayon d’impact d’un disque marginal pendant un scrub ou une traversée lourde.

5) Conceptions de special vdev bien réalisées

Si vous avez un special vdev composé de SSD en miroir dédiés aux métadonnées (et éventuellement aux petits blocs), vous pouvez rendre les métadonnées à la fois plus rapides et plus résilientes — si le special vdev lui-même est correctement redondant et surveillé. Dans de telles architectures, définir redundant_metadata=all pour des datasets critiques peut faire la différence entre « les métadonnées sont rapides » et « les métadonnées sont rapides et survivent à un mode de défaillance SSD étrange ».

Quand ça fait mal : compromis entre performances et espace

redundant_metadata n’est pas gratuit. Il peut vous mordre à trois endroits : amplification d’écriture, comportement de fragmentation et planification de capacité.

Amplification d’écriture et petites écritures aléatoires

Les écritures de métadonnées sont typiquement petites et aléatoires. Les dupliquer signifie plus de petites écritures aléatoires. Sur des pools HDD, c’est comme transformer une « latence acceptable » en « pourquoi tout est à 200ms ». Sur des pools SSD, vous ne le ressentirez peut-être pas immédiatement, mais vous augmentez quand même la charge d’écriture et potentiellement l’endurance et le comportement de garbage collection.

Si votre charge est sync-heavy (bases de données avec sync=standard et beaucoup de fsync, exports NFS avec sémantique sync), le chemin des métadonnées est sur la chaîne critique de latence. Les écritures supplémentaires de métadonnées peuvent apparaître comme des temps de commit plus élevés, qui se traduisent par de la latence additionnelle côté application. Personne n’appelle l’équipe de stockage pour la latence moyenne.

Surcharge d’espace invisible jusqu’à ce qu’elle le soit

L’overhead des métadonnées est généralement petit comparé aux données. « Généralement » fait beaucoup de travail dans cette phrase. Si vous stockez des milliards de petits objets, activez fortement les xattrs, ou conservez des historiques de snapshots profonds, les métadonnées peuvent devenir substantielles. Des copies supplémentaires de métadonnées peuvent vous pousser vers une utilisation élevée du pool, et une utilisation élevée du pool est là où l’allocation ZFS devient moins accueillante, la fragmentation augmente et les performances se dégradent.

C’est là que les gens sont surpris : ils n’étaient pas à court d’espace à cause des « données ». Ils étaient à court parce que le système de fichiers devait gérer les données, et la gestion a été dupliquée.

Pas la bonne solution pour « je veux plus de redondance »

Si votre objectif réel est « je veux que ce dataset survive à deux pannes de disque », redundant_metadata n’est pas votre outil. Choisissez la topologie mirror/RAIDZ en conséquence. Des copies supplémentaires de métadonnées aident pour certaines classes de corruption et d’illisibilité localisée ; elles ne modifient pas votre tolérance aux pannes fondamentale comme le fait la redondance des vdev.

Faits et contexte utiles pour les discussions

Voici des points courts et concrets qui aident quand vous êtes en revue de conception et que quelqu’un dit « pourquoi parlons-nous des métadonnées ? »

  1. ZFS a été conçu autour des sommes de contrôle de bout en bout, donc il peut détecter la corruption silencieuse plutôt que de servir des données erronées en toute discrétion. Cette détection n’est utile que s’il existe une source alternative valide (côté mirror, reconstruction par parité ou copie supplémentaire).
  2. Le copy-on-write rend la cohérence bon marché mais les métadonnées actives. Même des petites modifications peuvent toucher plusieurs blocs de métadonnées : mises à jour de dnode, blocs indirects, mises à jour de spacemap, etc.
  3. Le terme « ditto blocks » précède le nom de propriété moderne et reflète l’idée originale : conserver des copies supplémentaires de métadonnées critiques pour qu’un seul secteur mauvais ne puisse pas bricker la traversée du pool.
  4. Les scrubs ne sont pas que des « vérifications », ce sont des workflows de réparation sur des vdev redondants : ZFS lit, vérifie les sommes de contrôle et peut guérir en réécrivant depuis une bonne copie. Des copies supplémentaires de métadonnées peuvent augmenter la probabilité qu’une bonne copie existe.
  5. Les métadonnées ont tendance à être des I/O en petits blocs, ce qui est précisément le pire motif pour des vdev HDD et des dispositions parité : petites écritures aléatoires, sensibles à la latence.
  6. RAIDZ a une « taxe de reconstruction » : quand un secteur est mauvais, la lecture d’un bloc peut nécessiter la lecture de plusieurs colonnes et une reconstruction. Pour les métadonnées, cette taxe touche des opérations fréquentes (parcours de répertoires, énumération de snapshots).
  7. Une forte utilisation du pool change le comportement de l’allocateur, augmentant souvent la fragmentation et rendant les I/O de métadonnées plus dispersées. Des copies supplémentaires augmentent la pression sur l’espace libre plus tôt.
  8. Les special vdev ont été introduits pour traiter les goulots d’I/O de métadonnées en déplaçant les métadonnées vers des périphériques plus rapides ; mais ils introduisent aussi un nouveau domaine de défaillance qui doit être mis en miroir (ou mieux) parce que le perdre peut être catastrophique.
  9. « Les sauvegardes existent » n’est pas la même chose que « la restauration est possible ». Si la corruption des métadonnées empêche d’énumérer les snapshots ou de lire des flux send, vous pouvez avoir des bits sur disque et être bloqué opérationnellement.

Trois mini-récits issus du terrain en entreprise

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

Nous avons hérité d’un cluster de stockage qui « avait de la redondance », selon le document de passage de témoin. Le pool était en RAIDZ2, plein de disques, et les tableaux de bord étaient verts. L’hypothèse de l’équipe était : la parité = sécurité, donc l’ajustement des métadonnées est académique.

Puis un événement anodin : un scrub hebdomadaire a commencé, et un jour plus tard les développeurs se sont plaints qu’un registre de conteneurs « se bloquait aléatoirement ». Pas hors service — juste bloqué. Le pool n’était pas plein et il n’y avait pas de pannes de périphérique évidentes. Mais la latence a grimpé durant les opérations riches en métadonnées : listing de tags, garbage collection et extraction de couches anciennes. L’équipe applicative soupçonnait le réseau. L’équipe réseau suspectait le DNS. L’équipe stockage suspectait tout et rien.

zpool status montrait des erreurs de somme de contrôle sur un disque, mais le vdev était toujours ONLINE. RAIDZ2 « gérait ». La mauvaise hypothèse était que « gérer » signifie « aucun impact utilisateur ». En réalité, chaque fois que ZFS tombait sur certains blocs de métadonnées qui vivaient sur la région marginale de ce disque, il payait la pénalité de reconstruction. Sous la charge du scrub, ces lectures de métadonnées sont devenues fréquentes et coûteuses. Le système était correct ; il était aussi lent.

Nous avons remplacé le disque et les symptômes ont disparu. Plus tard, le postmortem a conduit à deux changements : nous avons traité les erreurs de somme de contrôle comme urgentes même si la redondance les masquait, et nous avons ajusté la stratégie de métadonnées pour les datasets les plus lourds. La leçon n’était pas « redundant_metadata aurait empêché cela ». C’était que les métadonnées sont le premier endroit où un matériel marginal devient visible, et que la parité n’offre pas de performances gratuites.

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

Dans un autre environnement : un système de build produisant des millions de petits artefacts. Le pool était SSD en RAIDZ, et l’équipe voulait maximiser la capacité. Quelqu’un a lu que la redondance supplémentaire des métadonnées « gaspille de l’espace » et a mis redundant_metadata=none sur les datasets d’artefacts. Ça semblait inoffensif. Les scrubs étaient propres. Les graphiques avaient l’air super. Des promotions ont été discutées.

Des mois plus tard, un bug de firmware (pas catastrophique, juste agaçant) a causé des erreurs de lecture occasionnelles sur un sous-ensemble de blocs d’un SSD. Avec RAIDZ, ZFS a reconstruit. Encore une fois, « géré ». Mais la charge était riche en métadonnées : parcours de répertoires, tempêtes de stat, et opérations de snapshot pendant le nettoyage de rétention. Un jour, un job de nettoyage a commencé à échouer pour détruire d’anciens snapshots à cause d’une « erreur I/O » sur un dataset. Pas tout le pool. Pas même tous les snapshots. Juste certaines opérations touchant des structures de métadonnées spécifiques.

Maintenant le retour de bâton : parce que les métadonnées n’avaient pas de copies physiques supplémentaires, les options de récupération étaient plus limitées. RAIDZ pouvait reconstruire certaines blocs, mais un bloc est devenu définitivement illisible après des tentatives répétées ; ZFS a signalé des erreurs permanentes liées aux métadonnées. Le dataset est devenu partiellement ingérable : le listing était lent et erratique, le nettoyage échouait, et les envois avaient des problèmes. Nous avons dû effectuer une remédiation plus disruptive : restaurer depuis une cible de réplication propre, ce qui a coûté du temps et de la crédibilité.

La leçon n’était pas « toujours mettre redundant_metadata=all ». C’était que l’« optimisation » a été faite sans comprendre le mode de panne qu’elle échangeait. L’optimisation de capacité est facile à justifier ; la complexité de récupération est plus difficile à quantifier jusqu’à ce que vous la viviez.

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

Un troisième récit, et c’est le moins glamour : une équipe qui faisait des scrubs routiniers, gardait une utilisation raisonnable du pool, et avait une séparation propre des datasets avec des propriétés sensées. Ils avaient aussi une politique : les datasets riches en métadonnées recevaient une protection supplémentaire, et ils utilisaient un special vdev en miroir pour les métadonnées sur leurs pools les plus chargés.

Un matin, un hôte a redémarré après une maintenance électrique. Il est remonté, mais quelques services étaient lents. Rien n’était « down », et c’est exactement le genre de situation où les gens perdent une demi-journée à se renvoyer la balle. L’ingénieur stockage a lancé un scrub et a immédiatement vu des erreurs de somme de contrôle qui ont été corrigées. Le système s’est guéri parce qu’il avait un endroit d’où guérir.

Ce n’est pas fini : la cause racine a été retracée à un câble HBA flaky qui corrompait occasionnellement des données en vol. La raison pour laquelle ce n’était pas un incident majeur était ennuyeuse : les sommes de contrôle l’ont détecté, la redondance l’a réparé, et les scrubs l’ont mis en évidence rapidement. Ils ont remplacé le câble, validé et sont passés à autre chose. Pas d’héroïsme. Pas de restauration durant le week-end. Pas de réunion dramatique « on a failli tout perdre ».

C’est la vraie condition de réussite : un système conçu de sorte que la panne ressemble à une maintenance routinière, pas à un événement qui définit une carrière.

Tâches pratiques : commandes et interprétation

Voici des tâches pratiques que vous pouvez exécuter sur un système ZFS. Les commandes sont écrites dans un shell de style Linux avec les outils OpenZFS. Ajustez les noms de pool/dataset pour votre environnement.

Task 1: Check the current redundant_metadata setting (and inheritance)

cr0x@server:~$ zfs get -r -o name,property,value,source redundant_metadata tank
NAME                 PROPERTY           VALUE  SOURCE
tank                 redundant_metadata all    default
tank/home            redundant_metadata all    inherited from tank
tank/registry         redundant_metadata none   local
tank/registry/blobs   redundant_metadata none   inherited from tank/registry

Interprétation : Vous cherchez des remplacements « local » qui ont pu être définis comme correctif rapide ou optimisation. « default » ou « inherited » n’est pas automatiquement correct ; cela signifie juste que personne ne l’a modifié.

Task 2: Change redundant_metadata safely on a single dataset

cr0x@server:~$ sudo zfs set redundant_metadata=all tank/registry
cr0x@server:~$ zfs get redundant_metadata tank/registry
NAME           PROPERTY           VALUE  SOURCE
tank/registry  redundant_metadata all    local

Interprétation : Cela affecte les nouvelles écritures de métadonnées pour ce dataset. Cela ne réécrira pas instantanément les métadonnées existantes. Si vous espériez un changement immédiat dans la distribution sur disque, vous serez déçu (et cette déception est plus sûre que l’alternative).

Task 3: Validate pool health and see if errors already exist

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Determine if the device needs to be replaced, and clear the errors
  see: none
config:

        NAME           STATE     READ WRITE CKSUM
        tank           ONLINE       0     0     0
          raidz2-0     ONLINE       0     0     0
            sda        ONLINE       0     0    12
            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

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

        tank/registry@daily-2025-12-01:/blobs/sha256/aa/...

Interprétation : Des erreurs de somme de contrôle sur un périphérique ne sont pas « correctes parce que RAIDZ2 ». Ce sont un symptôme. Des erreurs permanentes pointant vers un chemin de snapshot indiquent souvent des problèmes de métadonnées ou des blocs référencés affectant la vue de ce snapshot.

Task 4: Scrub on purpose, not by superstition

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank
  pool: tank
 state: ONLINE
status: scrub in progress since Tue Dec 24 10:11:22 2025
        1.23T scanned at 510M/s, 420G issued at 173M/s, 8.11T total
        0B repaired, 5.18% done, 0:07:42 to go

Interprétation : « Scanned » vs « issued » importe. Si « issued » est bien plus faible, le pool cherche/file ou est limité par les IOPS. Les pools riches en métadonnées montrent souvent fortement cet écart.

Task 5: Check space pressure (because it changes everything)

cr0x@server:~$ zpool list -o name,size,alloc,free,capacity,frag,health
NAME  SIZE  ALLOC  FREE  CAPACITY  FRAG  HEALTH
tank  10T   8.7T   1.3T  87%       52%   ONLINE

Interprétation : 87% plein et 52% fragmenté est la zone où « les petites écritures aléatoires de métadonnées » deviennent plus coûteuses. Si vous accordez la redondance des métadonnées sur un pool si plein, la planification de capacité fait partie de la correction.

Task 6: Identify metadata-heavy datasets by object count and logical space

cr0x@server:~$ zfs list -o name,used,refer,logicalused,logicalrefer,compressratio -r tank
NAME           USED  REFER  LOGICALUSED  LOGICALREFER  RATIO
tank           8.7T  128K   11.2T        128K          1.28x
tank/home      1.2T  1.2T   1.3T         1.2T          1.09x
tank/registry  6.8T  6.8T   9.4T         9.4T          1.38x

Interprétation : Cela ne montre pas directement les métadonnées, mais aide à trouver les datasets où le comportement logique vs physique et le churn peuvent indiquer beaucoup d’activité de pointeurs de blocs. Combinez avec le nombre de snapshots et la connaissance de la charge.

Task 7: Count snapshots and understand retention risk

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -r tank/registry | head
NAME                                USED  REFER  CREATION
tank/registry@hourly-2025-12-24-09   0B    6.8T   Tue Dec 24 09:00 2025
tank/registry@hourly-2025-12-24-08   0B    6.8T   Tue Dec 24 08:00 2025
tank/registry@daily-2025-12-23       12G   6.7T   Mon Dec 23 00:10 2025

Interprétation : Beaucoup de snapshots signifie beaucoup de chemins historiques de métadonnées. Si des opérations sur de vieux snapshots échouent, la redondance des métadonnées peut faire partie de la stratégie de résilience, mais vous avez aussi besoin de discipline de scrub et d’une rétention sensée.

Task 8: Confirm special vdev exists (metadata tier)

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
            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
        special
          mirror-1       ONLINE       0     0     0
            nvme0n1p1    ONLINE       0     0     0
            nvme1n1p1    ONLINE       0     0     0

Interprétation : Si vous avez un special vdev, il doit être redondant. S’il s’agit d’un seul périphérique, traitez-le comme une panne en attente d’être planifiée.

Task 9: Check where metadata is going (high-level behavior)

cr0x@server:~$ zpool get -o name,property,value,source feature@spacemap_histogram tank
NAME  PROPERTY                   VALUE  SOURCE
tank  feature@spacemap_histogram active local

Interprétation : Les fonctionnalités varient selon la plateforme et la version ; le point est de vérifier que votre pool prend en charge les outils de visibilité que vous voulez utiliser. Si votre plateforme a une introspection limitée, vous devrez peut-être vous appuyer davantage sur des symptômes de charge et les résultats des scrubs.

Task 10: Observe I/O pressure and latency (quick view)

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

avg-cpu:  %user %nice %system %iowait  %steal   %idle
           6.12  0.00    3.45   18.90    0.00   71.53

Device            r/s     w/s   rkB/s   wkB/s  await  svctm  %util
sda              32.0   210.0   820.0  4600.0  98.12   3.10  79.2
sdb              30.0   208.0   800.0  4550.0 102.55   3.20  80.1
nvme0n1         900.0   700.0 72000.0 64000.0   1.20   0.05   8.5

Interprétation : Un await élevé sur les HDD avec un faible débit indique souvent une saturation par I/O aléatoire — douleur classique des métadonnées. Une faible utilisation sur NVMe indique qu’il n’est probablement pas le goulot ; une utilisation élevée suggère une saturation du tier de métadonnées ou un special vdev mal dimensionné.

Task 11: Watch ZFS I/O stats (pool level)

cr0x@server:~$ zpool iostat -v tank 1 3
                               capacity     operations     bandwidth
pool                         alloc   free   read  write   read  write
---------------------------  -----  -----  -----  -----  -----  -----
tank                          8.7T   1.3T  2.10K  5.80K  180M   95M
  raidz2-0                    8.7T   1.3T  2.10K  5.80K  180M   95M
    sda                           -      -    350    970   30M   16M
    sdb                           -      -    350    970   30M   16M
    sdc                           -      -    350    970   30M   16M
    sdd                           -      -    350    970   30M   16M
    sde                           -      -    350    970   30M   16M
    sdf                           -      -    350    970   30M   16M
special                            -      -    900  1.10K  72M   64M
  mirror-1                         -      -    900  1.10K  72M   64M
    nvme0n1p1                      -      -    450    550   36M   32M
    nvme1n1p1                      -      -    450    550   36M   32M
---------------------------  -----  -----  -----  -----  -----  -----

Interprétation : Cela aide à confirmer si le trafic de métadonnées / petits blocs atterrit sur le special vdev ou si les HDD RAIDZ font le travail douloureux. Si le special vdev est absent, les IOPS de métadonnées atterrissent sur les vdev principaux.

Task 12: Check dataset knobs that commonly interact with metadata behavior

cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,atime,xattr,dnodesize,compression,redundant_metadata tank/registry
NAME           PROPERTY           VALUE
tank/registry  recordsize         128K
tank/registry  atime              off
tank/registry  xattr              sa
tank/registry  dnodesize          legacy
tank/registry  compression        zstd
tank/registry  redundant_metadata all

Interprétation : La stratégie de métadonnées ne vit pas seule. xattr=sa peut augmenter la densité de métadonnées dans les dnodes ; dnodesize affecte combien de métadonnées peuvent vivre « inline ». Ceux-ci peuvent changer la quantité d’I/O de métadonnées et le coût de leur duplication.

Task 13: Identify checksum errors early and clear only after remediation

cr0x@server:~$ zpool status -x
pool 'tank' has experienced checksum errors
cr0x@server:~$ sudo zpool clear tank
cr0x@server:~$ zpool status -x
all pools are healthy

Interprétation : Effacer les erreurs sert à tenir les comptes après avoir traité la cause (remplacement de disque, correction de câblage, scrub complet). Effacer d’abord supprime simplement la preuve et n’enseigne rien au système.

Task 14: Use a controlled file tree to see metadata costs in microcosm (lab technique)

cr0x@server:~$ mkdir -p /tank/testmeta
cr0x@server:~$ time bash -c 'for i in $(seq 1 200000); do echo x > /tank/testmeta/f_$i; done'
real    2m41.772s
user    0m20.118s
sys     1m39.332s

Interprétation : C’est un instrument brutal, mais il rend le coût des métadonnées visible. Répétez sur un dataset avec des réglages redundant_metadata différents (en labo) et comparez latence et stats I/O. Ne faites pas ça en production, sauf si vous aimez devoir vous expliquer.

Carnet de diagnostic rapide

Voici l’ordre que j’utilise quand un système est lent et que « le stockage pourrait être impliqué ». L’objectif est d’identifier si les métadonnées sont le goulot, et si les réglages de redondance y contribuent.

Premier : le pool est-il sain, ou payons-nous une taxe de reconstruction ?

cr0x@server:~$ zpool status -v tank

Regardez : erreurs de somme de contrôle, périphériques dégradés, scrub en cours, « permanent errors », erreurs de lecture répétées sur un même périphérique. Si vous voyez des incréments CKSUM, supposez un impact sur les performances même si le pool est ONLINE.

Second : Sommes-nous contraints par capacité/fragmentation ?

cr0x@server:~$ zpool list -o name,capacity,frag,alloc,free tank

Regardez : capacité > 80–85% et forte fragmentation. Si vous êtes presque plein, l’overhead de duplication des métadonnées est plus susceptible de nuire, et le comportement de l’allocateur peut dominer tout.

Troisième : est-ce la latence IOPS (type métadonnées) ou le débit (type données) ?

cr0x@server:~$ iostat -x 1 10

Regardez : un await élevé avec peu de KB/s pointe vers une pression d’I/O aléatoire — souvent métadonnées. Un KB/s élevé avec une util élevée pointe vers une saturation de débit séquentiel.

Quatrième : le special vdev fait-il son travail (si présent) ?

cr0x@server:~$ zpool status tank
cr0x@server:~$ zpool iostat -v tank 1 5

Regardez : special vdev occupé alors que les HDD sont calmes (bon : métadonnées offloadées) versus HDD occupés avec de petites I/O (métadonnées coincées sur la rust).

Cinquième : confirmer les réglages au niveau dataset sur le chemin chaud

cr0x@server:~$ zfs get -o name,property,value,source redundant_metadata,copies,recordsize,xattr,dnodesize,primarycache tank/registry

Regardez : copies accidentellement réglé à 2+ (grosse erreur fréquente), ou redundant_metadata réglé de façon incohérente avec la charge et la tolérance au risque.

Sixième : décider : corrigeons-nous le matériel, la charge, ou la configuration ?

Si des erreurs existent : corrigez le matériel d’abord. Si presque plein : corrigez la capacité d’abord. Si les IOPS de métadonnées sont le goulot : envisagez un special vdev (correctement miroré), réduisez le churn de métadonnées (politique de snapshots, comportement applicatif), puis considérez les réglages de redondance des métadonnées dans le contexte.

Erreurs courantes : symptômes et corrections

Mistake 1: Treating checksum errors as “non-urgent because redundancy”

Symptôme : zpool status montre des erreurs CKSUM sur un périphérique, le pool reste ONLINE, mais les scrubs ralentissent et les opérations de métadonnées deviennent instables.

Correction : Enquêter et remédier à la cause sous-jacente (disque, câble, HBA, backplane). Lancer un scrub après remplacement. Ensuite seulement effacer les erreurs.

Mistake 2: Using redundant_metadata=none as a blanket capacity optimization

Symptôme : Des mois plus tard vous voyez des erreurs permanentes liées à des chemins de snapshot ou des erreurs de traversée de répertoire durant la réplication/cleanup.

Correction : Réévaluer le risque. Envisager redundant_metadata=most ou all pour les datasets riches en métadonnées/critique, surtout sur RAIDZ. Associer avec scrubs et retention raisonnable.

Mistake 3: Confusing redundant_metadata with copies

Symptôme : Le pool se remplit « mystérieusement », la latence d’écriture augmente, et vous trouvez copies=2 activé sur de gros datasets.

Correction : Utiliser zfs get copies sur l’arbre, et réinitialiser là où inapproprié. Garder copies pour des cas d’utilisation étroits (petits datasets critiques sur pools non redondants, ou cas spéciaux), pas comme un bouton de fiabilité occasionnel.

Mistake 4: Building a special vdev without redundancy

Symptôme : Tout est rapide jusqu’à ce que le périphérique spécial meure, et alors le pool est dans un état catastrophique (souvent non importable ou manquant des métadonnées critiques).

Correction : Le special vdev doit être miroré (au minimum) et surveillé comme un composant de première classe. Traitez-le comme partie intégrante du design de redondance du pool.

Mistake 5: Expecting immediate results after changing the property

Symptôme : Vous définissez redundant_metadata=all et ne voyez aucun changement dans le comportement des erreurs ou des performances, alors vous le remettez à l’envers et le déclarez inutile.

Correction : Rappelez-vous : cela impacte les nouvelles écritures. Les bénéfices apparaissent au fur et à mesure que les métadonnées sont réécrites. Utilisez-le comme politique, pas comme bouton de panique.

Mistake 6: Ignoring pool utilization and fragmentation while tuning metadata

Symptôme : Tout changement semble empirer les choses, surtout sur des pools HDD RAIDZ ; la latence explose pendant les opérations de snapshot et les scrubs.

Correction : Récupérez de la capacité (supprimez des données, raccourcissez la rétention, ajoutez des vdev). Tuner sur un pool presque plein, c’est comme réarranger des meubles dans une maison en feu : techniquement possible, émotionnellement peu utile.

Listes de contrôle / plan étape par étape

Checklist A: Deciding what to set (policy-level)

  1. Classer les datasets par impact métier : « peut être restauré plus tard » vs « doit être en ligne ».
  2. Classer par charge : riche en métadonnées (beaucoup de petits fichiers, snapshots, répertoires) vs riche en données (gros fichiers séquentiels).
  3. Classer par topologie vdev : mirror vs RAIDZ ; et si un special vdev existe.
  4. Si RAIDZ + riche en métadonnées + haute criticité : penchez vers redundant_metadata=all (ou au moins most).
  5. Si mirror + matériel sain + pas riche en métadonnées : le défaut peut suffire ; concentrez-vous sur les scrubs et la surveillance.
  6. Si le pool est >85% plein : corrigez la capacité avant d’ajouter de l’overhead.

Checklist B: Rolling out the change safely

  1. Inventorier les réglages actuels :
cr0x@server:~$ zfs get -r -o name,property,value,source redundant_metadata tank
  1. Choisir un seul dataset sur le chemin chaud et le changer en premier :
cr0x@server:~$ sudo zfs set redundant_metadata=all tank/registry
  1. Suivre la baseline de performance avant/après avec des stats pool et périphériques :
cr0x@server:~$ zpool iostat -v tank 1 10
cr0x@server:~$ iostat -x 1 10
  1. Lancer un scrub dans une fenêtre contrôlée et comparer erreurs corrigées et débit :
cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank
  1. Étendre aux autres datasets seulement après avoir compris l’overhead.

Checklist C: If you suspect metadata IOPS bottleneck

  1. Confirmer que c’est la latence/IOPS, pas le débit (iostat -x).
  2. Confirmer que le pool n’est pas dégradé / en reconstruction (zpool status -v).
  3. Vérifier capacité/frag (zpool list).
  4. Vérifier si un special vdev existe et s’il est dimensionné/miroré (zpool status).
  5. Ce n’est qu’alors que vous ajustez les politiques de métadonnées (redundant_metadata, rétention snapshots, organisation des datasets).

FAQ

1) Should I always set redundant_metadata=all?

Non. C’est un bon choix par défaut pour les datasets critiques et riches en métadonnées sur des pools RAIDZ, spécialement avec une longue rétention de snapshots. Sur des mirrors, le gain d’intégrité incrémental est généralement plus faible, et l’overhead peut ne pas valoir le coût pour chaque dataset.

2) Is redundant_metadata a substitute for mirrors or RAIDZ2?

Non. Cela ne change pas la tolérance aux pannes au niveau vdev. Cela aide pour certaines corruptions et scénarios d’illisibilité de blocs en augmentant la probabilité qu’une copie alternative de métadonnées soit disponible.

3) What’s the difference between redundant_metadata and copies=2?

copies duplique aussi les blocs de données, ce qui peut être extrêmement coûteux en espace et en charge d’écriture. redundant_metadata cible uniquement les métadonnées, typiquement beaucoup moins cher, et est souvent l’outil le plus chirurgical.

4) Does changing redundant_metadata rewrite existing metadata?

Pas immédiatement. Cela affecte les nouvelles métadonnées écrites. Les blocs existants peuvent être réécrits au fil des modifications de fichiers, de la création/suppression de snapshots ou de la réallocation des blocs avec le temps. Considérez-le comme une politique tournée vers l’avenir.

5) Will this fix “permanent errors have been detected” messages?

Pas directement. Les erreurs permanentes signifient que ZFS n’a pas pu réparer un bloc à partir de la redondance disponible au moment où il en avait besoin. Des copies supplémentaires peuvent réduire la probabilité que cela se reproduise à l’avenir, mais vous devez toujours remédier aux dommages existants (restauration depuis une réplication/sauvegarde, ou suppression des snapshots/fichiers affectés si possible).

6) Does a special vdev make redundant_metadata unnecessary?

Non. Un special vdev améliore les performances des métadonnées et peut augmenter la résilience s’il est miroré et sain. Mais c’est toujours du matériel, et il peut toujours subir corruption ou erreurs de lecture. Des copies supplémentaires de métadonnées peuvent compléter un special vdev ; elles ne remplacent pas une bonne conception de redondance.

7) What are the most common signs that metadata is my bottleneck?

Forte attente I/O, await disque élevé avec faible débit, listings de répertoire lents, opérations de snapshot lentes, charges de petits fichiers lentes, et scrub « issued » bien inférieur à « scanned ». Aussi : performances qui se dégradent à mesure que le pool se remplit et se fragmente.

8) Can redundant_metadata make performance worse?

Oui, surtout sur pools HDD et charges riches en métadonnées. Vous ajoutez des écritures supplémentaires petites. Si vous êtes déjà limité par les IOPS, cela peut augmenter la latence. C’est pourquoi on le déploie par dataset et on mesure.

9) If I’m on mirrors, should I set it to none for performance?

Peut-être, mais ne le faites pas par réflexe. Les mirrors fournissent déjà un fort auto-guérison, donc le gain d’intégrité est moindre ; toutefois, l’overhead de duplication des métadonnées peut aussi être moindre que vous ne le pensez selon la charge. Testez sur un dataset représentatif, et n’optimisez pas la sécurité à moins d’être certain du mode de panne accepté.

10) What’s the most “boring correct” configuration choice here?

Pour les datasets critiques : garder des scrubs programmés, maintenir l’utilisation sous contrôle, utiliser des vdev redondants (mirror ou RAIDZ adéquat), et définir la stratégie de métadonnées de façon intentionnelle (souvent redundant_metadata=all pour les datasets RAIDZ riches en métadonnées). La plupart des catastrophes sont un empilement de petites décisions « on réparera ça plus tard ».

Conclusion

redundant_metadata est un de ces leviers ZFS qui ressemble à une case à cocher jusqu’à ce que vous ayez vécu un incident lié aux métadonnées. Ensuite, il commence à ressembler à une police d’assurance dont la prime se paie en petites écritures et en overhead de capacité. L’astuce est d’acheter la police là où elle compte : datasets avec un fort churn de métadonnées, de longues histoires de snapshots et un impact métier élevé — surtout sur des pools RAIDZ où la reconstruction sous stress est coûteuse.

Si vous ne retenez qu’une leçon opérationnelle : ne débattez pas de la redondance des métadonnées en abstraction. Mesurez la santé de votre pool, la capacité et la marge IOPS ; comprenez si les métadonnées sont sur le chemin critique ; puis définissez redundant_metadata intentionnellement par dataset. ZFS fera le calcul, mais il ne fera pas la priorisation pour vous.

← Précédent
Conteneurs Docker en lecture seule : durcir sans casser votre application
Suivant →
Proxmox « Disque non amorçable » : ordre de démarrage BIOS/UEFI, indicateurs de disque et procédure de récupération rapide

Laisser un commentaire