Certaines pannes ne commencent pas par une défaillance de disque ou un panic du noyau. Elles commencent par un dataset nommé data2, un point de montage qui “semblait correct”, et un administrateur bien intentionné qui a supposé qu’il était au bon endroit.
ZFS est exceptionnellement tolérant—jusqu’à ce qu’il ne le soit plus. Les noms sont la colle dans ZFS : ils relient les mountpoints, les propriétés, les snapshots, les quotas, la délégation, la réplication, la supervision et la mémoire humaine. Si vous nommez vos datasets comme un tiroir à bazar, vous déboguerez comme si vous étiez bandé. Si vous les nommez comme pour de la production, vous économiserez des heures chaque mois et parfois éviterez un après-midi très coûteux.
Ce que font vraiment les noms de dataset dans ZFS
Un nom de dataset ZFS ressemble à un chemin, et ce n’est pas un accident. C’est un espace de noms hiérarchique : pool/app/prod/postgres. Les barres obliques ont une sémantique. Ce nom est aussi une identité utilisée par des outils (zfs, zpool, travaux de réplication, logiciels de sauvegarde, supervision, routage d’alertes, délégation d’accès). Vous ne faites pas que “étiqueter” un dataset ; vous créez une poignée que le reste du système utilisera pour toujours.
Dans la plupart des piles de stockage, le nommage est cosmétique. Dans ZFS, le nommage influence :
- Héritage des propriétés : compression, recordsize, atime, sync, xattr, acltype, quotas/reservations. La hiérarchie parent/enfant du nommage est la manière dont vous modélisez les comportements par défaut et les exceptions.
- Comportement de montage :
mountpoint,canmount,sharenfs/sharesmb, et le montage implicite au démarrage. - Identité des snapshots : les snapshots sont adressés comme
dataset@snap. Vos choix de nommage déterminent si l’automatisation peut trouver et raisonner sur l’ensemble de snapshots correct. - Périmètre de réplication :
zfs send pool/app/prod@x | zfs receive backup/app/prodest une affirmation sur la hiérarchie et la sélection. Le nommage affecte ce que vous pouvez répliquer, exclure ou rediriger en toute sécurité. - Délégation et multi-tenant :
zfs allowfonctionne sur des noms de dataset. Des frontières propres comptent lorsque vous déléguez les droits de snapshot ou de montage. - Vitesse de réponse en incident : sous pression, les humains reconnaissent des motifs. Un nommage clair réduit « je pense que c’est ce dataset » à « c’est évidemment ce dataset ».
Les noms sont bon marché. Les renommages ne le sont pas. Oui, zfs rename existe et est souvent sûr. Mais le rayon d’impact inclut les mounts, exports, collages de type fstab, la supervision, les cibles de sauvegarde, les bookmarks de réplication, et tout ce que votre organisation a collé au nom ancien. Le moment le moins coûteux pour être cohérent est avant votre premier planning de snapshots en production.
Règle d’opinion : nommez les datasets pour les opérations, pas pour votre organigramme interne. Les équipes et produits changent. Les mountpoints et contrats de réplication ont tendance à rester collés comme du chewing-gum sous une chaussure.
Une convention de nommage ennuyeuse qui fonctionne vraiment
Voici une convention qui s’adapte de “une machine dans un placard” à “réplication multi-site avec conservation conforme”, sans devenir un hobby taxonomique.
Format
Utilisez cette forme :
<pool>/<scope>/<env>/<service>/<role>
Exemples :
tank/app/prod/postgres/datatank/app/prod/postgres/waltank/app/stage/api/logstank/shared/prod/hometank/infra/prod/monitoring/tsdb
Ce que chaque segment signifie :
- pool : un domaine de défaillance physique. N’essayez pas d’encoder “rapide/lent” dans les noms de datasets ; utilisez des pools ou des classes de vdev intentionnellement.
- scope : une limite opérationnelle grossière (communs :
app,infra,shared,backup,scratch). C’est la façon d’éviter la maladie “tout est sousdata”. - env :
prod,stage,dev, peut-êtredr. Oui, même sur des systèmes mono-hôte. Cela vous force à placer les défauts au bon endroit. - service : la chose pour laquelle on vous alerte. Gardez-la stable.
- role : uniquement lorsque nécessaire, pour séparer des profils de propriétés (par ex. WAL vs data, logs vs uploads, cache vs durable).
Règles de caractères (gardez-le ennuyeux volontairement)
- ASCII en minuscules. Chiffres autorisés.
- Utilisez des tirets entre les mots, pas des underscores. Choisissez-en un et tenez-vous-y ; j’ai choisi les tirets parce que c’est cohérent avec de nombreux schémas ops.
- Pas d’espaces. Pas de ponctuation fantaisie. Évitez les points sauf si vous avez une bonne raison.
- Gardez les segments courts mais explicites :
monitoringvaut mieux quemonquand vous le retrouvez dans six mois.
Pourquoi ne pas tout intégrer ? Parce que vous finirez par encoder : unité commerciale, code projet, centre de coût, numéro de ticket, et les phases de la lune. Les noms ZFS sont des identifiants opérationnels, pas un schéma de base de données. Mettez les métadonnées dans des tags dans votre CMDB, dans l’IaC, ou au moins dans des propriétés utilisateur zfs set org:*—nous y reviendrons.
Une citation qui devrait vivre au-dessus de votre terminal (idée paraphrasée) : Gene Kranz, flight director : “Soyez sévère et compétent.” Les conventions de nommage sont la partie compétence.
Blague #1 : Le nommage des datasets, c’est comme le fil dentaire : tout le monde reconnaît que c’est bon, et presque tout le monde commence après le premier incident douloureux.
Conception de la hiérarchie : découper là où les propriétés changent
Une hiérarchie de datasets n’est pas des “dossiers dans ZFS.” C’est un arbre d’héritage avec des mounts attachés. La meilleure hiérarchie est celle où chaque nœud représente une frontière de politique significative : compression, recordsize, quota, reservation, comportement sync, calendrier de snapshots, rétention, chiffrement et cibles de réplication.
Principe de conception : un dataset par profil de propriétés
Si deux chemins nécessitent des réglages différents, ils ont besoin de datasets différents. Ça ne signifie pas des milliers de datasets ; cela signifie que vous tracez des frontières là où les défauts cessent d’être sûrs.
Frontières communes qui méritent un dataset séparé :
- Données de base de données vs WAL/journal : modèles d’écriture différents, souvent un
recordsizedifférent, parfoislogbias. - Images de VM : gros blocs, snapshots fréquents, potentiellement
volblocksizepour les zvols, attention àcompression. - Logs : pas toujours pertinents à snapshotter ; utilisez un dataset séparé pour les exclure de la réplication et de la rétention.
- Uploads utilisateurs : frontières de quota, souvent besoin de snapshots, la compression aide souvent.
- Caches : définissez
com.sun:auto-snapshot=falseou des propriétés utilisateur similaires pour vos outils.
Principe de conception : les datasets parents sont des défauts politiques
Créez un dataset parent pour chaque paquet de politiques stable, réglez les propriétés là, et laissez les enfants hériter. Par exemple :
tank/app/prod: compression activée, atime désactivé, snapdir caché, choix de normalisation.tank/app/prod/postgres: tag de calendrier de snapshots, tag de groupe de réplication.tank/app/prod/postgres/dataet.../wal: recordsize/logbias ajustés par rôle.
Pourquoi c’est important : pendant un incident, vous voulez répondre “quelle politique s’applique ici ?” avec une commande. Un arbre sain rend la réponse évidente. Un arbre en désordre le transforme en archéologie.
Frontières de chiffrement : nommez-les pour que les humains n’essaient pas de déchiffrer la mauvaise chose
Si vous utilisez le chiffrement natif ZFS, les racines de chiffrement séparées (les datasets où encryption=on et où les clés résident) devraient être évidentes dans le nommage. Le cycle de vie du matériel de clé est une frontière opérationnelle aussi réelle qu’un VLAN.
Patterns qui fonctionnent :
tank/secure/prod/hr/...oùtank/secure/prodest une racine de chiffrement.- Ou un segment suffixe :
.../encseulement si vous êtes cohérent et que cela correspond à des frontières de clés réelles.
Patterns qui échouent :
- Datasets chiffrés aléatoires disséminés sous des parents non chiffrés avec des noms qui n’indiquent ni l’emplacement ni la frontière des clés.
Le nommage des datasets est la façon d’éviter qu’un moment “juste le monter” devienne “pourquoi la demande de clé s’affiche sur le mauvais hôte à 2h du matin.”
Mountpoints, canmount et le piège « où sont passés mes fichiers »
Les mountpoints ZFS sont puissants parce qu’ils sont automatiques. Ils sont aussi dangereux parce qu’ils sont automatiques.
Alignez les noms de dataset avec les mountpoints (la plupart du temps)
La configuration la plus propre est :
- Le nom du dataset correspond au chemin du mountpoint avec la même hiérarchie.
- Exemple :
tank/app/prod/postgres/dataest monté sur/srv/app/prod/postgres/data.
Cela n’est pas obligatoire, mais c’est bien pour l’opérationnel. Quand le mountpoint correspond à l’arbre des datasets, vous pouvez en inférer un à partir de l’autre. Sous stress, c’est de l’or.
Utilisez canmount=off pour les datasets “organisationnels”
Beaucoup de datasets existent pour porter des propriétés héritées et ne doivent pas être montés. Ceux-là devraient être non montables par défaut :
tank/app,tank/app/prod,tank/app/prod/postgresveulent souventcanmount=offavec unmountpointhérité ou défini mais non réellement monté.
Si vous ne faites pas ça, vous finirez par monter un dataset parent par-dessus l’arbre de mountpoints d’un enfant, masquant les enfants et embrouillant tout le monde. C’est ainsi que vous “perdez” des données qui sont toujours sur disque—juste pas visibles au chemin que vous pensez.
Quand le nommage casse le montage
La plupart des erreurs de nommage apparaissent comme des erreurs de montage :
- Datasets créés sous le mauvais parent (mauvaise politique appliquée, mauvais mountpoint hérité).
- Mountpoints définis manuellement de manière ad hoc qui ne correspondent plus à la hiérarchie.
- Clones créés et montés quelque part “temporaire” qui devient permanent.
Blague #2 : ZFS montera volontiers votre dataset par-dessus le répertoire contenant vos notes sur comment ne pas faire cela.
Snapshots et réplication : le nommage comme API d’automatisation
En pratique, le nommage des datasets devient une API pour votre automatisation. Les jobs de sauvegarde sélectionnent des datasets par préfixe. Les règles de réplication mappent des préfixes source vers des préfixes destination. Les politiques de rétention sont liées à des groupes de datasets. Si vous nommez les datasets de façon incohérente, votre automatisation devra devenir “intelligente”. L’automatisation intelligente est l’endroit où les bugs se cachent.
Nommer les snapshots : gardez-le prévisible, triable et facile à grep
Les noms de snapshot sont par dataset. La convention qui rassure humains et scripts :
- Préfixez par système :
auto-,replica-,pre-upgrade- - Incluez un timestamp de type ISO :
YYYYMMDD-HHMM - Optionnellement inclure la classe de rétention :
hourly,daily,weekly
Exemples de noms de snapshots :
auto-hourly-20251226-0300auto-daily-20251226-0000pre-upgrade-20251226-1452
À éviter :
- Espaces et timestamps locaux (
Dec-26,26-12-2025) - Noms uniquement humains (
before-change) sans timestamp - Surcharger le nom des snapshots avec d’autres sémantiques (“c’est aussi l’ID du ticket et le nom de l’ingénieur”)
Mapping de réplication : les noms doivent permettre des transformations réversibles
Les meilleures configurations de réplication sont celles où le nom de destination est une transformation déterministe du nom source. Exemple :
- Source :
tank/app/prod/postgres - Dest :
backup/app/prod/postgres
Cela vous permet de raisonner sur le failover, tester les restaurations et auditer avec des règles simples. Ça évite aussi le travail de détective “d’où vient ce dataset ?”.
Utilisez des propriétés utilisateur pour l’automatisation, pas des astuces dans le nom
ZFS prend en charge les propriétés utilisateur (souvent écrites org:* ou com.example:*). Elles héritent comme les propriétés natives. Elles sont idéales pour marquer les datasets pour les calendriers de snapshots, les groupes de réplication et les niveaux de supervision—sans l’encoder dans le nom.
Exemples :
org:backup=goldorg:owner=paymentsorg:rpo=15morg:pii=true
Les noms vous disent “ce que c’est”. Les propriétés vous disent “comment on le traite”. Ne confondez pas les deux.
Faits intéressants et contexte historique (parce que le nommage ne s’est pas compliqué par accident)
- Les noms de datasets ZFS précèdent le “tagging” moderne dans le cloud. Les premières équipes ZFS s’appuyaient sur le nommage parce que les propriétés utilisateur et les pratiques de métadonnées externes n’étaient pas courantes dans les workflows ops.
- L’espace de noms des datasets a été conçu pour se comporter comme un arbre de système de fichiers, mais le modèle d’héritage le rapproche plus d’un arbre de politiques que d’une simple liste de répertoires.
- ZFS sur Solaris a popularisé l’idée de “frontières administratives” via les datasets, bien avant que la plupart des admins Linux n’aient des primitives similaires par défaut.
- Les snapshots sont de première classe et peu coûteux, ce qui fait que les noms deviennent l’index de l’historique. Si vous ne trouvez pas le bon snapshot rapidement, “peu coûteux” devient “cher”.
- zfs send/receive a poussé le nommage dans la conception des sauvegardes, parce que les cibles de réplication sont identifiées par des noms de dataset plutôt que par des IDs opaques.
- L’héritage des propriétés explique pourquoi ZFS évite des fichiers de config globaux pour beaucoup de comportements. Cela déplace la complexité dans l’arbre de datasets—votre nommage est la façon de la gérer.
- De nombreux outils tiers de snapshot ont adopté des conventions de nommage comme “auto-”, transformant les noms de snapshots en une surface d’API de facto pour les scripts de rétention et de réplication.
- L’essor des plateformes conteneurisées a rendu courant “un dataset par locataire”, ce qui a rendu la délégation (
zfs allow) et un nommage propre plus précieux que jamais. - Le chiffrement natif a augmenté le coût d’une hiérarchie négligée, parce que les frontières de clés sont des frontières de dataset, et celles-ci s’expriment dans les noms.
Trois mini-récits d’entreprise depuis les tranchées du nommage
1) Incident causé par une mauvaise hypothèse : « Ce dataset est évidemment staging »
L’entreprise avait un pool de stockage unique nommé tank et quelques datasets : tank/db, tank/db2, tank/web, tank/tmp. Un ancien admin est parti, comme c’est souvent le cas. Les nouveaux ingénieurs ont hérité du système et d’un tableau de bord de supervision qui ne montrait que la capacité du pool.
Un déploiement a mal tourné et l’on-call a décidé de revenir en arrière en utilisant des snapshots. Ils ont vu tank/db et ont supposé que c’était la base de staging parce que staging “était plus petit”. Ils ont restauré un snapshot sur un clone, l’ont monté temporairement et ont copié des fichiers. Ça “a marché”, dans le sens où la base a démarré.
Puis le support client a commencé à recevoir des tickets. Les données semblaient plus anciennes que prévu. Le rollback avait été appliqué en production, pas en staging. La cause racine n’était pas un défaut de ZFS ; il a fait exactement ce qu’on lui a demandé. L’échec était d’identité : le nom du dataset n’encodeait pas l’environnement, et il n’y avait pas de tag de propriété fiable pour leur dire ce qu’ils touchaient.
La correction n’a pas été héroïque. Ils ont créé une nouvelle hiérarchie : tank/app/prod/postgres et tank/app/stage/postgres, ont déplacé les données avec une fenêtre d’indisponibilité planifiée, et ont ajouté des propriétés org:env et org:service. Après cela, un humain pouvait jeter un œil à zfs list sans jouer à la roulette avec la réalité.
2) Optimisation qui s’est retournée : « On gagnera du temps au montage en aplatissant tout »
Une autre organisation gérait un cluster de virtualisation chargé et a décidé que leur arbre de datasets était “trop profond”. Quelqu’un a prétendu que moins de datasets signifierait moins de surcharge et un démarrage plus rapide. Ils ont aplati un arbre soigneux en un layout plat : tank/vm-001, tank/vm-002, etc. Ils ont aussi mis les logs, images et espaces scratch comme répertoires dans chaque dataset VM.
Au début, c’était propre. Puis les quotas sont devenus un cauchemar. Certaines VMs avaient besoin de plafonds stricts, d’autres de reservations, et quelques-unes d’un recordsize différent pour des charges DB. Ils ont essayé de rattraper ça par la discipline par répertoire, ce que ZFS n’applique pas. La seule chose qui l’imposait était “se souvenir de se comporter”, ce qui n’est pas un système de contrôle.
Le point de rupture est arrivé lors de l’ajustement de la réplication. Ils voulaient répliquer seulement les données “durables”, pas le scratch. Avec le modèle plat, scratch et durable vivaient dans le même dataset, donc ils devaient soit tout répliquer soit rien. Ils ont fini par tout répliquer pour respecter le RPO, ce qui a augmenté la bande passante utilisée et allongé les fenêtres de réplication. Puis la fenêtre a heurté la purge nocturne des snapshots, et les envois ont commencé à échouer par intermittence.
Ils ne sont pas revenus à l’arbre original ; ils sont passés à un meilleur. Les VMs sont devenues des enfants sous un scope d’environnement et de cluster, et scratch/logs ont eu leurs propres datasets avec des drapeaux d’exclusion de snapshot. L’“optimisation” n’était pas un gain de performance ; c’était un échec de politique déguisé en simplification.
3) Ennuyeux mais correct : sélection par préfixe et frontière propre qui a sauvé la mise
Une société financière avait une règle de nommage stricte : tout ce qui impactait les clients vivait sous tank/app/prod. Le reste—artefacts de build, caches, restores de test—vivait sous tank/scratch ou tank/app/dev. Les gens se plaignaient que c’était bureaucratique. Ça l’était. Ça marchait aussi.
Pendant un incident de stockage, la latence a grimpé et le pool s’est rempli plus vite que prévu. L’équipe devait libérer de l’espace sans jouer à la roulette avec des suppressions. Parce que l’arbre avait des frontières propres, ils ont pu cibler d’abord les datasets à faible valeur : ils ont détruit d’anciens clones et snapshots sous tank/scratch et confirmé que tank/app/prod restait intact.
Puis ils ont audité la croissance des snapshots. Le nommage a rendu trivial d’identifier quel service générait le plus de delta de snapshot parce qu’il était groupé sous tank/app/prod/<service>. Ils ont pu limiter le fautif et stabiliser le système.
Personne n’a été promu pour ça. Personne n’a écrit un postmortem intitulé “Notre convention de nommage a sauvé la production.” Mais l’absence de chaos était le but. L’ennuyeux a fonctionné.
Tâches pratiques : commandes, sorties, ce que ça signifie, et la décision à prendre
Voici des tâches réelles que vous lancerez en construisant une convention de nommage, en auditant une existante, ou en déboguant à 02:17 avec votre café qui aiguise le jugement.
Task 1: List datasets with mountpoints to spot naming-to-path drift
cr0x@server:~$ zfs list -o name,mountpoint,canmount -r tank/app/prod
NAME MOUNTPOINT CANMOUNT
tank/app/prod /srv/app/prod off
tank/app/prod/postgres /srv/app/prod/postgres off
tank/app/prod/postgres/data /srv/app/prod/postgres/data on
tank/app/prod/postgres/wal /srv/app/prod/postgres/wal on
Ce que ça signifie : Les parents portent la politique (canmount=off), les enfants montent là où attendu, et les mountpoints reflètent la hiérarchie des datasets.
Décision : Si vous voyez un dataset monté ailleurs que prévu (par ex. /var/lib/postgresql alors que le nom suggère /srv), décidez d’aligner les mountpoints ou de renommer les datasets pour éviter que les humains ne devinent mal.
Task 2: Show inherited properties to confirm policy boundaries
cr0x@server:~$ zfs get -o name,property,value,source -r compression,atime,recordsize tank/app/prod/postgres
NAME PROPERTY VALUE SOURCE
tank/app/prod/postgres compression lz4 inherited from tank/app/prod
tank/app/prod/postgres atime off inherited from tank/app/prod
tank/app/prod/postgres recordsize 128K default
tank/app/prod/postgres/data recordsize 16K local
tank/app/prod/postgres/wal recordsize 128K default
Ce que ça signifie : Les défauts viennent de tank/app/prod, et data est réglé localement. Le nommage explique pourquoi data existe comme dataset séparé.
Décision : Si vous trouvez beaucoup d’overrides local dispersés, vous devez probablement insérer des parents intermédiaires pour porter des politiques partagées—puis renommer ou réorganiser en conséquence.
Task 3: Find “mystery datasets” that don’t fit the convention
cr0x@server:~$ zfs list -H -o name | egrep -v '^(tank/(app|infra|shared|backup|scratch)/)'
tank/data
tank/db2
tank/oldstuff
Ce que ça signifie : Ces datasets ne sont sous aucune portée reconnue.
Décision : Investigatez chacun : s’il est en production, migrez/renommez dans la convention ; s’il est obsolète, planifiez la suppression ; s’il est inconnu, mettez-le en quarantaine en posant readonly=on temporairement pendant que vous identifiez les propriétaires.
Task 4: Map dataset names to actual mounted filesystems
cr0x@server:~$ mount -t zfs | head
tank/app/prod/postgres/data on /srv/app/prod/postgres/data type zfs (rw,xattr,posixacl)
tank/app/prod/postgres/wal on /srv/app/prod/postgres/wal type zfs (rw,xattr,posixacl)
tank/shared/prod/home on /home type zfs (rw,xattr,posixacl)
Ce que ça signifie : Vous pouvez voir rapidement si quelque chose est monté où il “ne devrait pas” (comme monter un dataset sur / ou par-dessus /var involontairement).
Décision : Si un dataset est monté sur un répertoire critique de façon inattendue, traitez-le comme un incident : confirmez si le répertoire sous-jacent contient du contenu caché et si un dataset parent a été monté accidentellement.
Task 5: Confirm you’re not hiding children with an accidentally mounted parent
cr0x@server:~$ zfs get -o name,property,value,source canmount,mountpoint tank/app/prod
NAME PROPERTY VALUE SOURCE
tank/app/prod canmount off local
tank/app/prod mountpoint /srv/app/prod local
Ce que ça signifie : canmount=off empêche ce dataset d’être monté et de masquer ses enfants.
Décision : Si canmount=on sur des parents organisationnels, mettez-le sur off sauf si vous avez une raison délibérée. Puis remontez et vérifiez la visibilité.
Task 6: Audit snapshot sprawl by dataset prefix (naming pays here)
cr0x@server:~$ zfs list -t snapshot -o name,used,creation -s creation | tail -5
tank/app/prod/postgres/data@auto-hourly-20251226-0200 312M Fri Dec 26 02:00 2025
tank/app/prod/postgres/data@auto-hourly-20251226-0300 298M Fri Dec 26 03:00 2025
tank/app/prod/postgres/wal@auto-hourly-20251226-0200 28M Fri Dec 26 02:00 2025
tank/app/prod/postgres/wal@auto-hourly-20251226-0300 31M Fri Dec 26 03:00 2025
tank/app/prod/postgres/data@pre-upgrade-20251226-0322 1M Fri Dec 26 03:22 2025
Ce que ça signifie : Vous pouvez voir les deltas par dataset et si votre nommage de snapshot est cohérent. Les noms de snapshots se trient bien et signalent l’intention.
Décision : Si vous voyez des deltas de snapshot inattendus sous un dataset qui suggère “logs” ou “cache”, séparez-le en datasets distincts et excluez les bruyants des snapshots/réplication.
Task 7: Identify datasets that should not be snapshotted (and prove it)
cr0x@server:~$ zfs get -r -o name,property,value org:auto-snapshot tank/app/prod
NAME PROPERTY VALUE SOURCE
tank/app/prod org:auto-snapshot true local
tank/app/prod/postgres org:auto-snapshot true inherited from tank/app/prod
tank/app/prod/postgres/data org:auto-snapshot true inherited from tank/app/prod
tank/app/prod/api/logs org:auto-snapshot false local
Ce que ça signifie : Vous utilisez des propriétés utilisateur pour marquer l’éligibilité aux snapshots, et vous pouvez l’outrepasser sur un dataset feuille proprement.
Décision : Si vous encodez “nosnap” dans le nom du dataset, arrêtez. Utilisez des propriétés utilisateur pour pouvoir changer la politique sans renommer les actifs.
Task 8: Find space hogs by dataset and decide whether the name matches the value
cr0x@server:~$ zfs list -o name,used,refer,compressratio -s used | tail
tank/app/prod/postgres/data 1.21T 1.19T 1.62x
tank/app/prod/vm/images 1.44T 1.40T 1.08x
tank/shared/prod/home 1.88T 1.75T 1.37x
Ce que ça signifie : Vous voyez quels datasets consomment de l’espace, et les ratios de compression donnent des indices sur le contenu.
Décision : Si vm/images est énorme et se compresse peu, ça peut être normal ; si logs est énorme et a des snapshots, c’est un mauvais signe—séparez-le et ajustez la politique.
Task 9: Check quotas and reservations (naming should make this obvious)
cr0x@server:~$ zfs get -o name,property,value,source quota,reservation tank/app/prod/api
NAME PROPERTY VALUE SOURCE
tank/app/prod/api quota 500G local
tank/app/prod/api reservation none default
Ce que ça signifie : Ce dataset a un quota strict. S’il se remplit, le service échoue—prévisible.
Décision : Si vous avez des quotas, le nom du dataset doit refléter la frontière (par service, par locataire, par rôle). Si des quotas sont sur un dataset ambigu comme tank/data, vous invitez des pannes surprises.
Task 10: Find who “owns” a dataset (without guessing from the name)
cr0x@server:~$ zfs get -o name,property,value -s local,inherited -r org:owner,org:service,org:env tank/app/prod/postgres
NAME PROPERTY VALUE
tank/app/prod/postgres org:owner payments
tank/app/prod/postgres org:service postgres
tank/app/prod/postgres org:env prod
tank/app/prod/postgres/data org:owner payments
tank/app/prod/postgres/data org:service postgres
tank/app/prod/postgres/data org:env prod
Ce que ça signifie : La propriété et l’environnement sont des métadonnées explicites, pas du savoir tribal.
Décision : Si vous ne pouvez pas répondre “qui pager pour ce dataset” à partir des propriétés, corrigez cela. Les noms seuls ne constituent pas une structure d’organisation stable.
Task 11: Safely rename a dataset (and verify what changes)
cr0x@server:~$ sudo zfs rename tank/db2 tank/app/prod/postgres
cr0x@server:~$ zfs list -o name,mountpoint tank/app/prod/postgres
NAME MOUNTPOINT
tank/app/prod/postgres /srv/app/prod/postgres
Ce que ça signifie : L’identité du dataset a changé, et si les mountpoints sont hérités ou définis avec soin, il arrive à l’endroit attendu.
Décision : Avant de renommer en production, inventairez les dépendances : scripts de sauvegarde, cibles de réplication, règles de supervision, exports, configs de conteneurs. Si vous ne pouvez pas inventorier, vous n’êtes pas prêt à renommer—créez un nouveau dataset et migrez.
Task 12: Plan replication mapping using names and confirm snapshot presence
cr0x@server:~$ zfs list -t snapshot -o name -s creation -r tank/app/prod/postgres | tail -3
tank/app/prod/postgres/data@auto-hourly-20251226-0200
tank/app/prod/postgres/data@auto-hourly-20251226-0300
tank/app/prod/postgres/data@pre-upgrade-20251226-0322
cr0x@server:~$ sudo zfs send -R tank/app/prod/postgres@auto-hourly-20251226-0300 | sudo zfs receive -u backup/app/prod/postgres
Ce que ça signifie : -R réplique le sous-arbre. -u reçoit sans monter immédiatement (utile pour des cutovers contrôlés).
Décision : Si votre sous-arbre inclut des trucs inutiles (logs, caches), ne répliquez pas tout. Séparez les datasets pour que la réplication de sous-arbre corresponde à l’intention métier. Le nommage rend la séparation évidente et sélectionnable.
Task 13: Detect inconsistent case and illegal creativity
cr0x@server:~$ zfs list -H -o name | egrep '[A-Z ]'
tank/App/Prod/API
Ce que ça signifie : Quelqu’un a créé un dataset avec des segments en majuscules, ce qui tend à casser les conventions et les scripts qui supposent des minuscules.
Décision : Renommez en minuscules maintenant. Plus vous attendez, plus la colle autour de l’erreur durcit.
Task 14: Spot “manual mountpoint snowflakes” that will bite during restores
cr0x@server:~$ zfs get -H -o name,value,source mountpoint -r tank | awk '$3 ~ /^local/ {print}'
tank/app/prod/postgres/data /var/lib/postgresql/data local
tank/shared/prod/home /home local
Ce que ça signifie : Ces datasets ont des overrides de mountpoint locaux. Certains sont normaux (/home est intentionnel) ; d’autres sont suspects (postgres/data monté dans /var alors que votre convention suggère /srv).
Décision : Décidez si votre convention est “les noms reflètent les mountpoints” ou “les noms sont logiques, les mountpoints sont hérités”. Mixer les deux sans documentation est la façon dont les restores montent au mauvais endroit.
Playbook de diagnostic rapide : trouver le goulot vite
Quand le stockage est “lent”, vous n’avez pas le temps d’admirer votre arbre de datasets. Il vous faut une séquence courte et brutale qui vous mène à une hypothèse exploitable. Le nommage compte ici parce qu’il réduit l’espace de recherche.
Première étape : est-ce la capacité au niveau du pool ou la fragmentation qui cause la pression ?
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 7.25T 6.91T 352G - - 52% 95% 1.00x ONLINE -
Interprétation : 95% plein et 52% de fragmentation, c’est une fête de latence à laquelle vous n’avez pas répondu.
Décision : Libérez de l’espace maintenant (supprimez snapshots/clones dans des scopes à faible valeur comme scratch), ou ajoutez de la capacité. Ne touchez pas au recordsize pendant que le pool étouffe.
Deuxième étape : quel sous-arbre de datasets génère les écritures et deltas de snapshots ?
cr0x@server:~$ zfs list -o name,used,refer -r tank/app/prod | tail
tank/app/prod/api 220G 180G
tank/app/prod/postgres 1.24T 1.20T
tank/app/prod/vm 1.50T 1.45T
Interprétation : Les gros consommateurs sont clairs. Un nommage correct signifie que vous savez ce que ça représente sans explorer les répertoires.
Décision : Concentrez l’investigation sur le(s) dataset(s) en tête, pas sur l’ensemble du pool.
Troisième étape : la charge est-elle liée au sync, aux métadonnées, ou aux misses du cache de lecture ?
cr0x@server:~$ zfs get -o name,property,value -r sync,recordsize,atime,primarycache tank/app/prod/postgres
NAME PROPERTY VALUE
tank/app/prod/postgres sync standard
tank/app/prod/postgres recordsize 128K
tank/app/prod/postgres atime off
tank/app/prod/postgres primarycache all
tank/app/prod/postgres/data recordsize 16K
Interprétation : Si le service est sensible à la latence d’écriture et que vous observez une forte latence d’écritures sync, examinez le SLOG, les réglages sync et le comportement fsync de l’application. Si c’est la latence de lecture et des misses cache, regardez la taille de l’ARC et le working set.
Décision : Déterminez si c’est un problème de propriétés (tuning au niveau dataset) ou un problème matériel/pool. Le nommage aide parce que des rôles comme wal devraient avoir leur propre dataset, permettant un tuning ciblé.
Quatrième étape : vérifiez le montage avant d’accuser les disques
cr0x@server:~$ zfs list -o name,mountpoint,canmount -r tank/app/prod/postgres
NAME MOUNTPOINT CANMOUNT
tank/app/prod/postgres /srv/app/prod/postgres off
tank/app/prod/postgres/data /srv/app/prod/postgres/data on
tank/app/prod/postgres/wal /srv/app/prod/postgres/wal on
Interprétation : Si quelque chose est monté de travers, vous pouvez voir des “problèmes de performance” qui sont en réalité “vous écrivez sur le système de fichiers racine, pas sur ZFS” ou “vous écrivez dans un répertoire caché sous un mount”.
Décision : Corrigez d’abord les mounts. Puis mesurez à nouveau la performance. La moitié des incidents de stockage sont des incidents d’identité de chemin.
Erreurs fréquentes : symptômes → cause racine → correction
1) Symptom: “My files disappeared after reboot”
Cause racine : Un dataset parent monté par-dessus un répertoire qui contenait des fichiers (ou par-dessus les mountpoints d’enfants), masquant le contenu. Souvent parce que canmount=on sur des datasets organisationnels.
Correction : Mettez canmount=off sur les parents, assurez-vous que les datasets feuilles ont les mountpoints corrects, et recherchez les fichiers cachés en démontant temporairement et en inspectant le répertoire sous-jacent.
2) Symptom: Snapshots are massive and replication windows keep slipping
Cause racine : Logs/cache/temp partage un dataset avec des données durables, donc les snapshots capturent le churn. Le nommage révèle souvent ça : tank/app/prod/api contient logs/ et cache/ comme répertoires.
Correction : Scindez en .../data, .../logs, .../cache. Excluez logs/cache de la politique de snapshot et de réplication via des propriétés utilisateur.
3) Symptom: Quota hits the wrong team
Cause racine : Quotas placés sur un dataset qui ne représente pas une frontière de propriété réelle (ex. tank/shared), ou un nommage ambigu qui encourage l’usage mixte.
Correction : Réorganisez pour que chaque tenant/service ait un dataset avec un nom clair et un org:owner explicite. Appliquez les quotas là, pas à une couche partagée confuse.
4) Symptom: Backups miss a service after a rename
Cause racine : Sélection de sauvegarde basée sur des noms de dataset codés en dur, et les renommages ont été faits sans mettre à jour la pipeline. Ou les sauvegardes utilisaient des filtres de préfixe, mais le nouveau nom est sorti du préfixe attendu.
Correction : Standardisez les préfixes (tank/app/prod) et sélectionnez par préfixe plus propriétés utilisateur (ex. org:backup=gold). Traitez les renommages de dataset comme des changements gérés avec vérification explicite des dépendances.
5) Symptom: Replication receives into a messy destination tree
Cause racine : Le nommage de la destination ne reflète pas la source, donc les receives atterrissent dans des chemins bizarres. Quelqu’un a fait des receives “rapides” dans backup/incoming et n’a jamais normalisé.
Correction : Définissez une règle de mapping déterministe : tank/* vers backup/* pour les scopes durables, et recevez dans des cibles stables. Utilisez zfs receive -u et définissez les mountpoints intentionnellement.
6) Symptom: “Why does this dataset have weird properties?”
Cause racine : Overrides de propriétés dispersés parce que la hiérarchie n’inclut pas de nœuds de politique intermédiaires. Le nommage montre typiquement ça : profondeur incohérente, groupement de services ad-hoc.
Correction : Insérez des datasets intermédiaires qui représentent des ensembles de politiques (ex. tank/app/prod, tank/app/prod/postgres). Déplacez les enfants sous eux et supprimez les overrides locaux redondants.
7) Symptom: Monitoring and alert routing is inconsistent
Cause racine : Les noms de datasets n’encoder pas une identité de service stable, et il n’y a pas de propriétés utilisateur pour mapper datasets vers propriétaires/environnements.
Correction : Faites respecter <scope>/<env>/<service> tôt dans le nom et ajoutez org:owner, org:env, org:service partout. La supervision doit lire ça, pas parser des chaînes aléatoires.
Checklists / plan étape par étape
Étape par étape : établir une convention de nommage sans casser la production
- Inventoriez les datasets actuels : listez noms, mountpoints et propriétés clés. Identifiez les valeurs aberrantes et les noms ambigus.
- Définissez vos scopes top-level : choisissez 3–6 qui reflètent la réalité opérationnelle (
app,infra,shared,backup,scratch). - Définissez les environnements : au minimum
prodetnonprod(oustage/devsi vous les utilisez vraiment). - Choisissez les noms de services : identités stables, dignes d’être pagées. Évitez les noms de projet internes.
- Décidez de la base de mountpoint :
/srvvs/var/libvs legacy. Écrivez-le. La cohérence vaut mieux que l’idéologie. - Créez des datasets parents avec
canmount=off: ce sont vos transporteurs de politique. - Définissez les défauts de politique au bon niveau : compression, atime, acltype/xattr, snapdir, et vos propriétés utilisateur org.
- Migrez un service à la fois : créez de nouveaux datasets, rsync/copy, basculez les mounts, vérifiez, puis retirez les anciens datasets.
- Mettre à jour l’automatisation : calendriers de snapshot, réplication, supervision, règles de sauvegarde.
- Verrouillez-le : ajoutez un contrôle préliminaire dans la provisioning/IaC qui refuse les noms non conformes.
Checklist : règles de nommage à faire respecter en revue
- Chaque dataset de production vit sous
<pool>/app/prod(ou votre équivalent). - Chaque service a un sous-arbre unique :
.../<service>. - Des datasets séparés existent lorsque les propriétés diffèrent (DB data/WAL/logs/cache/uploads/VM images).
- Les parents qui existent seulement pour grouper ont
canmount=off. - Les mountpoints sont soit systématiquement alignés aux noms, soit des exceptions documentées—jamais “peu importe”.
- Des propriétés utilisateur existent pour
org:owner,org:env,org:serviceet les paliers de sauvegarde/réplication. - Les noms de snapshots suivent une convention temporelle triable et cohérente.
- Les cibles de réplication reflètent le nom source avec un mapping déterministe.
Checklist : quand vous vous apprêtez à renommer un dataset
- Confirmez qu’il n’y a pas de références codées en dur dans les jobs de backup et de réplication.
- Confirmez que la supervision utilise des propriétés/préfixes qui continueront à correspondre.
- Confirmez que les mountpoints et exports sont corrects après le renommage.
- Planifiez un rollback : si le renommage cause des problèmes, pouvez-vous renommer en arrière rapidement ?
- Communiquez : les noms de datasets sont une API partagée ; traitez-les comme un changement d’interface.
FAQ
1) Do dataset names have to match mountpoints?
Non. Mais s’ils ne correspondent pas, vous devez être cohérent et délibéré. En production, un mapping prévisible réduit les erreurs humaines. Si vous héritez de mountpoints legacy, gardez des noms logiques et tracez le mapping via la propriété mountpoint et la documentation, pas par intuition.
2) How deep should my dataset hierarchy be?
Aussi profond que vos frontières de politique l’exigent, et pas plus. Si les propriétés ne diffèrent pas, un dataset séparé est généralement du bruit. Si les propriétés diffèrent, ne pas scinder est une dette technique qui porte intérêts.
3) Should I include region/host in the dataset name?
Généralement non. Le pool vit déjà sur un hôte, et les cibles de réplication doivent mapper les noms entre hôtes. Région/hôte appartient à l’inventaire système et au nom du pool de destination, pas à chaque chemin de dataset.
4) What about multi-tenant systems?
Utilisez une frontière tenant : tank/app/prod/<service>/tenants/<tenant-id> (ou customers). Placez quotas et délégation à cette frontière. Ne regroupez pas plusieurs tenants dans un seul dataset à moins qu’ils partagent le même sort et la même politique.
5) Should I encode retention policy in the dataset name?
Non. Encodez la rétention dans des propriétés utilisateur (ex. org:backup=gold, org:retention=daily-30) ou dans la configuration de l’outil de snapshots. Les noms doivent identifier la charge ; les propriétés définissent le traitement.
6) Is it okay to have datasets named “data”, “data2”, “misc”?
En laboratoire, oui. En production, c’est une panne qui attend de se produire. Si vous avez besoin d’un fourre-tout, appelez-le scratch et traitez-le comme supprimable sans regret.
7) Can I rename datasets safely in production?
Souvent oui, techniquement. Opérationnellement, le risque est l’écosystème autour du nom. Si des scripts, la supervision, des exports ou des cibles de backup réfèrent l’ancien nom, vous allez les casser. Renommez uniquement quand vous pouvez auditer les dépendances, ou migrez en créant de nouveaux datasets et en déplaçant les données.
8) How do snapshots affect naming strategy?
Les snapshots sont adressés comme dataset@snap, donc les noms de dataset et de snapshot forment un identifiant combiné que consomment humains et outils. Choisissez des noms lisibles dans cette forme combinée et triables par timestamp.
9) What’s the quickest win if my naming is already messy?
Créez des scopes top-level propres et placez-y les nouvelles charges. Puis migrez progressivement les pires cas. Ajoutez aussi org:owner et org:env partout pour router les alertes et décisions sans parser les noms.
10) Should I use one pool or multiple pools to express “tiers”?
Si les tiers représentent du matériel différent ou des domaines de défaillance distincts, utilisez des pools différents. Si les tiers ne sont que des politiques sur le même matériel, les datasets suffisent. N’encodez pas les tiers dans les noms quand le stockage sous-jacent ne diffère pas réellement.
Conclusion : prochaines étapes qui tiennent
Si vos noms de datasets sont aujourd’hui un musée de décisions passées, n’essayez pas de tout réparer en un week-end. Corrigez comme un SRE : par incréments, avec des garde-fous, et en gardant l’incident suivant à l’esprit.
- Choisissez une convention et consignez-la dans un endroit que les gens consultent réellement pendant la provisioning et les revues.
- Créez les datasets parents politiques (
app/prod,app/stage,infra/prod,scratch) aveccanmount=off. - Ajoutez des propriétés utilisateur pour
org:owner,org:envetorg:service. Faites consommer ces propriétés par l’automatisation plutôt que de parser les noms. - Scindez un dataset à fort churn (logs/cache) hors d’un dataset durable et observez la réduction immédiate de la croissance des snapshots et du temps de réplication.
- Appliquez la conformité dans l’IaC ou les scripts de provisioning : refusez les datasets qui ne correspondent pas aux règles. Les humains n’oublieront pas ; le tooling le fera.
Un bon nommage n’accélérera pas vos disques. Il accélérera vos décisions—et en production, c’est souvent la même chose.