En production, un « disque plein » est rarement un événement isolé. C’est une réaction en chaîne : un fichier de log cesse de tourner, une base panique, une file se remplit, et soudainement le canal d’incident est rempli de personnes répétant « mais df dit qu’il y a de l’espace. » ZFS vous donne des outils étonnamment précis pour éviter ce bazar — à condition de comprendre la différence entre l’espace qui existe et l’espace que votre dataset peut réellement écrire.
Ceci est un guide pratique et approfondi sur le refreservation ZFS : ce qu’il garantit réellement, ce qu’il ne garantit pas, comment il interagit avec les quotas et les snapshots, et comment l’utiliser pour maintenir les applications critiques en vie pendant que tout le reste se dispute les derniers octets. L’objectif n’est pas une exactitude académique. L’objectif est de ne plus jamais voir un pool parfaitement « sain » mettre hors service un service de niveau 0 parce que quelques Gio restants ont été bouffés par quelque chose d’ennuyeux.
Ce qu’est le refreservation (et pourquoi il existe)
refreservation est une propriété de dataset ZFS qui réserve de l’espace en fonction des données référencées pour ce dataset. En clair : c’est ZFS qui dit : « Quoi qu’il arrive dans ce pool, ce dataset aura au moins N octets disponibles pour écrire, tant que le pool lui-même n’a pas déjà atteint le point d’impossibilité physique. »
Le « ref » compte. ZFS est copy-on-write. L’espace « used » d’un dataset ne se limite pas à ce qui se trouve dans son état de filesystem actuel. Les snapshots peuvent maintenir des blocs anciens. Les clones peuvent partager des blocs. Les suppressions ne libèrent pas toujours l’espace comme vous le pensez. C’est ainsi qu’on se retrouve avec l’argument classique ZFS :
- Application : « J’ai supprimé 500 Go. Pourquoi ne puis-je pas écrire 10 Go ? »
- ZFS : « Parce que ces 500 Go sont encore référencés par des snapshots, des clones ou d’autres datasets. Bien tenté. »
refreservation est conçu pour protéger la capacité d’un dataset à continuer d’écrire même lorsque son propre historique (snapshots) ou sa relation avec d’autres datasets (clones) rend la comptabilité d’espace peu évidente.
Une façon opérationnelle de le décrire : le refreservation est la manière d’empêcher les « datasets importants » d’être affamés par les « datasets intéressants ». Important : bases de données, files journaux, magasins de métadonnées, volumes de démarrage de VM. Intéressant : tout ce que des humains peuvent y déverser, en particulier des logs, des buckets d’uploads, des artefacts de build, ou des zones temporaires « temporaires depuis 2019 ».
Blague #1 : Le refreservation, c’est comme mettre votre déjeuner dans le frigo du bureau avec votre nom dessus — sauf que ça marche vraiment.
Faits intéressants et contexte historique
L’ingénierie du stockage est pleine d’« idées nouvelles » qui sont en réalité de vieilles idées avec de meilleurs outils. Quelques points de contexte qui aident à comprendre le refreservation :
- ZFS a été conçu pour l’intégrité de bout en bout, pas seulement pour la gestion de capacité. Les contrôles d’espace comme les quotas et les reservations existent parce que « correct mais plein » casse encore les applications.
- Les files systèmes copy-on-write compliquent les suppressions. Les files systèmes traditionnelles libèrent généralement des blocs à la suppression ; ZFS ne libère des blocs que lorsqu’ils ne sont plus référencés. Les snapshots sont la cause la plus fréquente.
- Le « paradoxe df » est antérieur à ZFS. Même sur des systèmes plus anciens, les blocs réservés, l’overhead du filesystem et l’allocation différée provoquaient des moments « df indique libre ». ZFS rend simplement les raisons plus puissantes — et plus confuses.
- Le provisionnement fin est devenu courant en virtualisation et a apporté une nouvelle classe d’incidents : les invités pensent avoir de l’espace ; le backend n’est pas d’accord à 3 h du matin. Les reservations ZFS sont une des méthodes les plus honnêtes pour gérer le compromis thin vs thick.
- Les snapshots sont passés de « fonction de sauvegarde » à « par défaut opérationnel ». Quand les équipes ont commencé à faire des snapshots fréquemment (horaire, toutes les 15 minutes, parfois toutes les 5), la pression sur l’espace est devenue une préoccupation quotidienne.
- « Garder 20 % libre » n’est pas de la superstition. De nombreux systèmes de stockage (y compris ZFS) voient leurs performances et leur flexibilité d’allocation se dégrader à l’approche du plein. Le refreservation ne vainc pas la physique.
- L’héritage des propriétés ZFS est à la fois une fonctionnalité et un piège. Les reservations et quotas peuvent hériter de façon inattendue ; le refreservation est souvent défini au niveau du dataset précisément parce que « taille unique » échoue.
- Refquota/refreservation ont été façonnés par la douleur réelle des administrateurs. Les propriétés « ref » existent parce que « used » peut inclure de l’espace que vous ne pouvez pas vraiment libérer (snapshots/clones).
Un modèle mental : espace référencé vs disponible
Si vous administrez ZFS assez longtemps, vous finissez avec deux registres mentaux :
- Propriété logique : ce qu’un dataset semble contenir maintenant.
- Réalité physique : quels blocs sont encore référencés quelque part dans le pool.
ZFS expose cette séparation via les propriétés d’espace des datasets. La sortie exacte varie selon la plateforme (OpenZFS sur Linux vs dérivés illumos), mais les idées sont stables :
used: espace total consommé par le dataset et ses descendants, y compris les snapshots (selon le contexte) et l’overhead.referenced: espace référencé par l’état courant du dataset (hors snapshots).usedbydataset,usedbysnapshots,usedbychildren: le meilleur découpage pour répondre à « où est parti l’espace ? ».available: ce que ZFS estime pouvoir être écrit dans le dataset, après quotas/reservations et contraintes du pool.
refreservation est lié à referenced. Pensez-y comme : « je veux garantir que ce dataset peut augmenter ses octets référencés d’au moins N, indépendamment des bagages de snapshots ailleurs. » Les mécanismes sont subtils, mais opérationnellement l’effet est clair : il préencode de l’espace du pool que les autres datasets ne peuvent pas réclamer.
Reservation vs refreservation vs quotas
ZFS offre plusieurs leviers qui sonnent similaire. Ils ne sont pas interchangeables. Voici la cartographie pratique :
reservation
reservation réserve de l’espace pour un dataset et ses descendants (selon la structure). C’est une garantie « cet arbre obtient au moins N octets ». Utile quand vous traitez un dataset comme un conteneur pour de nombreux enfants et que vous voulez une tranche minimale du pool protégée.
refreservation
refreservation concerne l’espace référencé du dataset (pas les snapshots). C’est l’outil plus précis quand vous tenez à la capacité d’un dataset à continuer d’écrire son état live actuel même lorsque des snapshots existent et que les suppressions ne rendent pas immédiatement l’espace.
quota
quota limite la quantité d’espace qu’un dataset (et typiquement ses descendants) peut consommer. C’est un plafond « tu ne peux pas dépasser ceci ». Bon pour le contrôle multi-tenant. Mauvais si vous le définissez et l’oubliez.
refquota
refquota limite l’espace référencé (données live), pas les snapshots. C’est souvent ce que vous voulez quand vous ne voulez pas que les snapshots soient la raison pour laquelle un dataset refuse des écritures — bien que vous soyez toujours contraint par l’espace global du pool.
Une règle de décision rapide
- Si vous voulez limiter les données live d’une application : utilisez
refquota. - Si vous voulez limiter tout y compris la prolifération des snapshots : utilisez
quota. - Si vous voulez garantir une tranche minimale pour les écritures live d’un dataset : utilisez
refreservation. - Si vous voulez garantir une tranche minimale pour tout un sous-arbre : utilisez
reservation.
Blague #2 : Si les quotas sont un régime, les refreservations sont la préparation des repas — moins excitantes, plus efficaces, et tout le monde les déteste jusqu’à ce que la crise arrive.
Comment ZFS applique le refreservation (ce qui est réellement garanti)
Les reservations ZFS ne créent pas d’espace magique ; ce sont des zones d’exclusion. Lorsque vous définissez un refreservation, ZFS réduit ce que les autres datasets voient comme disponible parce que cet espace est réservé.
Trois vérités opérationnelles importantes :
- Le refreservation n’aide que si le pool a de la place pour le respecter. Si le pool est vraiment plein (ou effectivement plein à cause de l’espace de sécurité et des besoins en métadonnées), ZFS ne peut pas allouer des blocs qu’il n’a pas. Le refreservation est une politique, pas une loi de la thermodynamique.
- Le refreservation ne réserve pas « l’espace des snapshots ». Il s’agit de la croissance des données référencées/live. Les snapshots peuvent toujours consommer le pool et créer des problèmes, simplement sans voler la tranche garantie pour les écritures live de ce dataset.
- Le refreservation peut faire échouer d’autres datasets plus tôt — et c’est le but. C’est un mécanisme de priorisation. Votre dataset d’archive de logs doit échouer avant votre dataset de base de données.
Aussi, ZFS est honnête mais pas toujours intuitif : la valeur available sur un dataset reflète déjà ces contraintes de politique. Si votre refreservation est importante, zfs list pour les autres datasets affichera moins de disponible, même si le pool a de l’espace brut libre.
Trois mini-histoires du monde de l’entreprise
Mini-histoire #1 : L’incident causé par une fausse hypothèse (« Les snapshots sont des backups, non ? »)
Une entreprise de taille moyenne exploitait une API client backed par PostgreSQL sur ZFS. La disposition du stockage semblait propre : un pool, un dataset pour la base, un dataset pour le WAL, et un dataset pour les logs. Ils prenaient des snapshots fréquents parce que ça semblait responsable. Et ça l’était — jusqu’à la nuit où ça ne l’était plus.
Un développeur a lancé un job de backfill qui a créé une grande table temporaire puis l’a supprimée. L’équipe a vu l’utilisation du filesystem de la base monter puis redescendre. Tout le monde a soufflé. Mais le pool n’a pas suivi. Parce que les snapshots retenaient les blocs, l’espace « libéré » n’était pas réellement libre. Le pool a dérivé vers le plein au cours des heures suivantes à mesure que les écritures normales continuaient.
À environ 95 % d’utilisation effective du pool, les performances se sont dégradées. La latence a augmenté. Autovacuum a commencé à thrash. Puis le dataset WAL a rencontré ENOSPC. PostgreSQL a fait ce que font les bases quand elles ne peuvent pas écrire le WAL : il a cessé d’être une base.
La fausse hypothèse était subtile : « Si la base supprime des données, le pool récupère de l’espace. » Sur ZFS avec snapshots, ce n’est pas garanti. Ils n’avaient pas de refreservation sur le WAL, pas de refquota pour limiter la croissance temporaire, et leur politique de rétention de snapshots était « pour toujours jusqu’à ce qu’on pense à nettoyer. » La correction n’a pas été héroïque : ils ont ajouté un refreservation pour le WAL dimensionné pour couvrir les pics d’écriture, plafonné le dataset de la base avec refquota, et établi des durées de rétention des snapshots avec application.
Le postmortem contenait une ligne que j’ai vue de nombreuses fois : « Nous avons traité les snapshots comme des backups. » Les snapshots sont une machine à remonter le temps attachée à votre couche d’allocation. Ils sont incroyablement utiles — simplement pas gratuits.
Mini-histoire #2 : L’optimisation qui s’est retournée contre eux (« Tout en thin ! »)
Une autre organisation a consolidé plusieurs services sur un seul pool ZFS pour simplifier l’exploitation. Ils ont déplacé des disques de VM et des volumes de conteneurs dans des datasets et se sont fortement appuyés sur le provisionnement thin. Ça semblait efficace : haute utilisation, peu de gaspillage, tout le monde content. Les finances adoraient.
Puis quelqu’un a « optimisé » en retirant un ensemble de reservations de datasets. La logique semblait solide en réunion : « Les reservations gaspillent de l’espace. On peut récupérer de la capacité et augmenter la densité. » Ils ont supprimé les reservations de quelques datasets d’infra, y compris celui contenant des volumes de boot VM critiques.
Deux semaines plus tard, une pipeline de build est partie en vrille. Elle a rempli un dataset d’artefacts avec des blobs de plusieurs Go. Parce qu’aucune place n’était réservée, le dataset d’artefacts a consommé sans vergogne le maigre espace restant du pool. Quand un hyperviseur a essayé d’écrire sur un disque VM (une petite mise à jour de métadonnées, rien de dramatique), l’écriture a échoué. Soudainement, des VMs qui avaient beaucoup d’espace apparent à l’intérieur de l’invité ne pouvaient pas valider des écritures au niveau stockage. Résultat : remontages en lecture seule et beaucoup de « comment est-ce possible ? »
La leçon n’était pas « le thin provisioning est mauvais. » La leçon était : le thin provisioning sans règles de priorité, c’est du hasard. Les reservations/refreservations sont ces règles. L’équipe a réintroduit des garanties pour les volumes de boot et les bases, et ils ont placé le dataset d’artefacts derrière un quota plus un pool d’« overflow » séparé. La densité a un peu baissé. Le sommeil s’est beaucoup amélioré.
Mini-histoire #3 : La pratique ennuyeuse mais correcte qui a sauvé la mise (« Protéger le journal »)
Une équipe de paiements faisait tourner une file de messages dont la durabilité dépendait d’un journal write-ahead. La file n’était pas glamour, mais c’était le système d’enregistrement des travaux en cours. Quelqu’un dans l’équipe avait déjà été brûlé par des incidents de stockage plein, alors il a fait quelque chose de profondément pas sexy : il a créé un dataset dédié pour le journal et a défini un refreservation basé sur le taux d’ingestion dans le pire des cas et le temps de réponse aux incidents.
Des mois plus tard, un flag de debug « inoffensif » a été activé pendant une escalade client. Les logs ont explosé. Pas de façon mignonne — de façon « téraoctets par jour ». Le dataset de logs a tout avalé, snapshots inclus, et le pool est passé de confortable à tendu en quelques heures.
Mais la file a continué à fonctionner. Le dataset du journal avait encore de l’espace pour écrire parce que son refreservation avait taillé une tranche que le dataset de logs ne pouvait pas voler. L’incident a été bruyant — alertes, nettoyage, corrections de politique de rétention — mais il n’a pas été catastrophique. Pas de messages perdus, pas d’état corrompu, pas de restauration nocturne depuis une sauvegarde.
C’est à cela que sert le refreservation : pas à rendre les pools plus grands, mais à faire tomber les pannes sur les bonnes cibles. Quand ça déraille, vous voulez que le dataset le moins important soit le premier à hurler.
Tâches pratiques (commandes + interprétation)
Voici des tâches pratiques que vous pouvez exécuter sur un système OpenZFS (couramment Linux avec ZFS-on-Linux/OpenZFS). Les commandes supposent que vous avez les privilèges. Remplacez les noms de pool/dataset pour correspondre à votre environnement.
Task 1: Get the pool’s health and capacity reality
cr0x@server:~$ zpool status -v
pool: tank
state: ONLINE
scan: scrub repaired 0B in 0 days 00:12:41 with 0 errors on Sun Dec 22 02:10:11 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
errors: No known data errors
Interprétation : Avant d’ajuster des propriétés, confirmez que vous ne déboguez pas autour d’un pool dégradé. Les reservations ne vous sauveront pas de disques défaillants ou d’un pool qui ne peut pas allouer à cause d’erreurs.
Task 2: See pool-level free space and fragmentation hints
cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
NAME SIZE ALLOC FREE CAP FRAG HEALTH
tank 7.25T 6.10T 1.15T 84% 29% ONLINE
Interprétation : Un CAP élevé et une FRAG en hausse sont les conditions où « ça devrait marcher » devient « pourquoi c’est lent et ça échoue ? » Si vous êtes au-dessus de ~85–90 % de manière constante, vous êtes en zone de danger indépendamment des reservations.
Task 3: Inventory datasets and their available space
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint
NAME USED AVAIL REFER MOUNTPOINT
tank 6.10T 1.02T 192K /tank
tank/db 2.40T 220G 2.10T /tank/db
tank/db-wal 180G 120G 175G /tank/db-wal
tank/logs 1.60T 140G 1.20T /tank/logs
tank/artifacts 1.90T 90G 1.50T /tank/artifacts
Interprétation : avail ici est ce qui compte pour les applications. C’est déjà ajusté pour les reservations/quotas. Si un dataset critique a peu de avail, vous n’avez pas un problème théorique — vous avez un incident à court terme.
Task 4: Show reservation-related properties for all datasets
cr0x@server:~$ zfs get -r -o name,property,value,source reservation,refreservation,quota,refquota tank
NAME PROPERTY VALUE SOURCE
tank reservation none default
tank refreservation none default
tank quota none default
tank refquota none default
tank/db reservation none default
tank/db refreservation 300G local
tank/db quota none default
tank/db refquota 3T local
tank/db-wal reservation none default
tank/db-wal refreservation 200G local
tank/db-wal quota none default
tank/db-wal refquota none default
tank/logs reservation none default
tank/logs refreservation none default
tank/logs quota 2T local
tank/logs refquota none default
Interprétation : Si vous ne pouvez pas répondre « quels datasets sont garantis en espace ? » à partir d’une seule commande, vous travaillez à l’instinct. Cette vue rend la politique explicite.
Task 5: Set a refreservation for a critical dataset
cr0x@server:~$ sudo zfs set refreservation=200G tank/db-wal
cr0x@server:~$ zfs get refreservation tank/db-wal
NAME PROPERTY VALUE SOURCE
tank/db-wal refreservation 200G local
Interprétation : Cela réserve 200G d’espace du pool pour la croissance référencée du dataset WAL. Si vous surdimensionnez, vous pouvez priver les autres datasets — dimensionnez donc en fonction des débits d’écriture réels et du temps de réponse aux incidents.
Task 6: Confirm how refreservation affects other datasets’ available space
cr0x@server:~$ zfs list -o name,avail tank/logs tank/artifacts tank/db-wal
NAME AVAIL
tank/logs 90G
tank/artifacts 40G
tank/db-wal 120G
Interprétation : Si vous venez de définir un refreservation, attendez-vous à voir le AVAIL des autres datasets diminuer. Ce n’est pas un bug ; c’est la politique qui fait son travail.
Task 7: See where space is tied up (dataset vs snapshots)
cr0x@server:~$ zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren,refer -t filesystem tank/db
NAME USED USEDBYDATASET USEDBYSNAPSHOTS USEDBYCHILDREN REFER
tank/db 2.40T 2.10T 260G 40G 2.10T
Interprétation : Si USEDBYSNAPSHOTS est important, les suppressions ne libéreront pas d’espace. Si votre app a « libéré » des données mais que le pool ne l’a pas fait, ce découpage est votre point de départ.
Task 8: List snapshots and identify big offenders
cr0x@server:~$ zfs list -o name,used,refer,creation -t snapshot tank/db | tail -n 5
tank/db@auto-2025-12-23-0000 12.4G 2.06T Tue Dec 23 00:00 2025
tank/db@auto-2025-12-23-0100 9.8G 2.07T Tue Dec 23 01:00 2025
tank/db@auto-2025-12-23-0200 15.1G 2.07T Tue Dec 23 02:00 2025
tank/db@auto-2025-12-23-0300 11.2G 2.08T Tue Dec 23 03:00 2025
tank/db@auto-2025-12-23-0400 10.6G 2.08T Tue Dec 23 04:00 2025
Interprétation : Le USED d’un snapshot est l’espace unique à ce snapshot (par rapport aux autres snapshots). De grands chiffres corrèlent souvent avec des workloads très volatils (bases, CI artifacts) et peuvent justifier un resserrement de la rétention ou le déplacement des workloads.
Task 9: Check whether a dataset is blocked by a quota/refquota rather than pool fullness
cr0x@server:~$ zfs get -o name,property,value quota,refquota tank/logs
NAME PROPERTY VALUE
tank/logs quota 2T
tank/logs refquota none
Interprétation : Si une app rencontre ENOSPC mais que le pool n’est pas plein, les quotas sont un suspect principal. Les quotas représentent un « plein local » même quand le pool a de la capacité.
Task 10: Measure real referenced headroom vs refreservation size
cr0x@server:~$ zfs get -o name,property,value referenced,refreservation tank/db-wal
NAME PROPERTY VALUE
tank/db-wal referenced 175G
tank/db-wal refreservation 200G
Interprétation : Avec referenced à 175G et refreservation à 200G, vous garantissez essentiellement environ 25G de croissance référencée supplémentaire (sous réserve de la réalité du pool). Si referenced est déjà au-dessus de la refreservation, vous ne « devez » pas d’espace supplémentaire ; la reservation est effectivement consommée.
Task 11: Use a reservation instead when you want to protect a subtree
cr0x@server:~$ sudo zfs set reservation=500G tank/db
cr0x@server:~$ zfs get reservation tank/db
NAME PROPERTY VALUE SOURCE
tank/db reservation 500G local
Interprétation : C’est approprié quand tank/db contient plusieurs enfants (tablespaces, backups, zones temporaires) et que vous voulez protéger le groupe. À utiliser prudemment : les reservations de sous-arbre peuvent avoir des effets étonnamment « collants » sur la disponibilité du pool.
Task 12: Remove a refreservation safely (and verify impact)
cr0x@server:~$ sudo zfs set refreservation=none tank/db-wal
cr0x@server:~$ zfs get refreservation tank/db-wal
NAME PROPERTY VALUE SOURCE
tank/db-wal refreservation none default
Interprétation : Supprimer des garanties doit être traité comme retirer un disjoncteur : ça peut aller, mais vous changez les modes de défaillance. Faites-le avec une raison explicite et un plan de rollback.
Task 13: Check pool “slop space” constraints (why the last few GiB don’t behave)
cr0x@server:~$ zfs get -o name,property,value special_small_blocks 2>/dev/null
cr0x@server:~$ zfs list -o name,avail tank
Interprétation : Beaucoup d’opérateurs sont surpris par la limite pratique où ZFS devient conservateur près du plein pour préserver l’opérabilité du pool. Si vous concevez des garanties, ne comptez pas sur « 100 % de la taille du pool ». Laissez de la marge.
Task 14: Identify whether deletes are blocked by snapshots/clones
cr0x@server:~$ zfs get -o name,property,value used,referenced,usedbysnapshots tank/artifacts
NAME PROPERTY VALUE
tank/artifacts used 1.90T
tank/artifacts referenced 1.50T
tank/artifacts usedbysnapshots 380G
Interprétation : Si les données « supprimées » faisaient partie de l’état référencé mais que des snapshots les conservent, usedbysnapshots augmente. C’est souvent l’explication de « rm -rf n’a pas résolu le problème ».
Task 15: Create a “sacrificial” dataset with a quota to absorb garbage
cr0x@server:~$ sudo zfs create tank/scratch
cr0x@server:~$ sudo zfs set quota=200G tank/scratch
cr0x@server:~$ zfs get -o name,property,value quota tank/scratch
NAME PROPERTY VALUE
tank/scratch quota 200G
Interprétation : C’est la version opérationnelle de « mettez les trucs sales dans une pièce avec une serrure. » Vous pouvez orienter les jobs temporaires ici pour qu’ils rencontrent un mur avant les datasets de production.
Feuille de diagnostic rapide
Quand quelque chose échoue avec ENOSPC, écritures lentes, ou « l’espace disponible n’a pas de sens », ne partez pas en exploration au hasard. Vérifiez ceci dans l’ordre.
1) Pool reality: is the pool actually full or unhealthy?
cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
cr0x@server:~$ zpool status -v
Ce que vous recherchez : CAP > ~90%, fragmentation très élevée, ou état dégradé. Si le pool est en feu, les ajustements au niveau dataset sont secondaires.
2) Dataset constraints: quota/refquota/reservation/refreservation
cr0x@server:~$ zfs get -r -o name,property,value,source quota,refquota,reservation,refreservation tank
Ce que vous recherchez : Un dataset atteignant un quota/refquota, ou d’autres datasets « perdant » de la disponibilité parce qu’une grosse reservation/refreservation existe ailleurs.
3) Space held by snapshots and children
cr0x@server:~$ zfs list -o name,used,usedbydataset,usedbysnapshots,usedbychildren,refer -t filesystem tank
cr0x@server:~$ zfs list -t snapshot -o name,used,creation | tail
Ce que vous recherchez : Gros usedbysnapshots sur des datasets très changeants ; un dataset enfant consommant la reservation du parent ; des snapshots multipliant la croissance.
4) If performance is the symptom: check pool I/O saturation and latency
cr0x@server:~$ iostat -x 1 5
cr0x@server:~$ zpool iostat -v 1 5
Ce que vous recherchez : Haute utilisation disque, latences await longues, et charge inégale entre dispositifs. Un pool proche du plein peut aussi amplifier l’amplification d’écriture et le churn des métadonnées.
5) Confirm the app’s view (filesystem vs ZFS)
cr0x@server:~$ df -hT /tank/db /tank/db-wal
cr0x@server:~$ zfs list -o name,avail,used,refer tank/db tank/db-wal
Ce que vous recherchez : Un écart entre df et zfs list signifie généralement que c’est la politique ZFS (quota/reservation) ou la réalité des snapshots qui décide, pas ce que l’OS pense en termes génériques.
Erreurs courantes (symptômes + corrections)
Mistake 1: “We set refreservation and now the pool ‘lost’ space.”
Symptôme : D’autres datasets affichent un AVAIL drastiquement réduit. Quelqu’un affirme que vous « avez consommé » des centaines de gigaoctets sans écrire de données.
Ce qui se passe : Les reservations/refreservations réduisent la disponibilité partagée ; c’est la garantie qui est honorée.
Correction : Dimensionnez correctement les garanties en fonction des écritures pires cas et du temps de réponse. Si vous devez protéger plusieurs services, répartissez des garanties plus petites plutôt qu’un énorme découpage. Vérifiez avec :
cr0x@server:~$ zfs get -r -o name,property,value refreservation,reservation tank
Mistake 2: Assuming refreservation protects you from snapshots filling the pool
Symptôme : Vous avez défini refreservation sur un dataset critique, mais les écritures échouent quand le pool est presque plein.
Ce qui se passe : Si le pool ne peut pas allouer de blocs à cause du remplissage global (plus le besoin de ZFS pour des métadonnées et une marge opérationnelle), la garantie ne peut pas conjurer de l’espace.
Correction : Faites respecter la rétention des snapshots et maintenez une marge de capacité. Traitez « pool > 90% » comme un incident, pas comme une métrique acceptable. Investiguer l’utilisation des snapshots :
cr0x@server:~$ zfs list -o name,used,usedbysnapshots -t filesystem tank | sort -h -k3
Mistake 3: Using reservation when you meant refreservation (or vice versa)
Symptôme : Vous réservez de l’espace sur un dataset parent, mais un enfant rencontre toujours ENOSPC ; ou vous avez défini refreservation sur un parent et il ne se comporte pas comme une « garantie de sous-arbre ».
Ce qui se passe : reservation et refreservation s’appliquent différemment dans la hiérarchie et en termes de comptabilité.
Correction : Décidez si vous protégez les écritures live d’un seul dataset (refreservation) ou un sous-arbre complet (reservation). Vérifiez l’héritage et l’endroit où la reservation est appliquée :
cr0x@server:~$ zfs get -r -o name,property,value,source reservation,refreservation tank/db
Mistake 4: Treating quotas as “safe defaults” without monitoring
Symptôme : Un service échoue des écritures alors que le pool a largement d’espace libre.
Ce qui se passe : Le dataset a atteint quota ou refquota. Du point de vue de l’app, c’est un disque plein.
Correction : Surveillez used par dataset vs quotas et alertez tôt. Confirmez rapidement :
cr0x@server:~$ zfs get -o name,property,value quota,refquota tank/service
Mistake 5: Making guarantees bigger than your “oh no” runway
Symptôme : Des datasets moins critiques rencontrent ENOSPC constamment ; les équipes commencent à contourner les contrôles ; vous finissez dans un cycle whack-a-mole.
Ce qui se passe : Vous avez sur-alloué de l’espace garanti par rapport à la taille du pool et aux schémas d’utilisation réels. Les garanties deviennent une contention permanente.
Correction : Faites la somme des reservations et refreservations et comparez-la aux cibles réalistes d’espace libre du pool. Vous voulez que les garanties protègent les charges clés, pas étranglent tout le reste.
cr0x@server:~$ zfs get -r -H -o value refreservation,reservation tank | awk '
{ if ($1 != "none") sum += $1 }
END { print sum }'
Interprétation : Cette approche brute nécessite la gestion des unités dans de vrais scripts, mais le point opérationnel tient : les garanties totales doivent tenir dans votre plan de capacité avec une marge.
Listes de contrôle / plan étape par étape
Checklist A: Introducing refreservation for a critical service (without surprises)
- Mesurez le pic d’écriture. Regardez le volume d’écriture pires 1–6 heures du service, plus l’overhead et le temps de réponse aux incidents.
- Confirmez la marge du pool. Si le pool vit au-dessus de 85–90 %, corrigez la capacité d’abord. Les garanties sur un pool chroniquement plein ne font que réarranger les chaises.
- Créez un dataset dédié. Ne partagez pas un dataset entre « écritures critiques » et « tout le reste ».
- Définissez
refreservationsur le dataset. Commencez modestement, puis ajustez selon le comportement observé. - Optionnellement, plafonnez les voisins bruyants. Ajoutez
quotaourefquotaaux datasets de logs/artefacts pour qu’ils échouent avant le tier-0. - Validez les changements de disponibilité. Confirmez que le
availdes autres datasets n’est pas tombé sous des seuils opérationnels sûrs. - Simulez le mode de défaillance. Remplissez un dataset non critique jusqu’à son quota et confirmez que le dataset critique continue d’écrire.
Checklist B: Capacity incident response when a pool is trending full
- Identifiez les plus gros consommateurs (
zfs listet découpageusedbysnapshots). - Vérifiez la rétention des snapshots et supprimez les snapshots appropriés (pas au hasard) quand c’est sûr.
- Confirmez qu’aucun dataset en fuite n’est sans contrainte (pas de quota) alors que les datasets critiques manquent de garanties.
- Réduisez le churn : arrêtez le job qui génère la tempête d’écriture.
- Ensuite seulement, envisagez des changements de propriétés d’urgence (réductions temporaires de quota, reservations temporaires) avec étapes de rollback explicites.
Step-by-step: A sane “tiering” policy with refreservation
Voici un modèle pratique qui fonctionne bien dans les pools multi-services en entreprise :
- Datasets Tier 0 (doivent continuer d’écrire) : définir refreservation ; envisager un pool dédié ou des vdevs spéciaux si applicable ; alerter quand le avail descend sous la marge garantie.
- Datasets Tier 1 (importants mais dégradables) : quotas/refquotas modérés ; petites reservations si nécessaire.
- Datasets Tier 2 (best effort) : les quotas sont obligatoires ; snapshots à courte rétention ; accepter ENOSPC comme échec contrôlé.
FAQ
1) Does refreservation guarantee free space even if the pool is 99% full?
Non. Il garantit une disponibilité au niveau politique tant que le pool peut physiquement allouer. Les pools proches du plein peuvent échouer les allocations à cause des besoins en métadonnées et des marges de sécurité opérationnelles de ZFS.
2) What’s the simplest way to tell if ENOSPC is due to quota or pool fullness?
Vérifiez à la fois le pool et le dataset :
cr0x@server:~$ zpool list -o name,cap,free
cr0x@server:~$ zfs get -o name,property,value quota,refquota tank/the-dataset
Si le pool a de l’espace libre mais que le dataset a un quota/refquota proche de sa limite, c’est une contrainte locale du dataset.
3) Why does deleting files not free space on ZFS?
Parce que les snapshots (et parfois les clones) peuvent encore référencer les blocs. Supprimer retire les références du filesystem live, mais les blocs restent alloués tant que quelque chose les référence.
4) Should I use refreservation for databases?
Souvent oui pour les WAL/journaux et autres volumes critiques pour la durabilité, car ce sont les premiers éléments à faire tomber le service quand les écritures échouent. Associez-le à une discipline sur les snapshots et à une surveillance de capacité.
5) Can refreservation help with “df shows space but writes fail”?
Il peut prévenir une classe de défaillance : être affamé par d’autres datasets — mais il ne résout pas les mauvaises configurations de quota ou un pool effectivement plein. Utilisez zfs list comme source de vérité pour la disponibilité des datasets.
6) Is refreservation the same as preallocating a file?
Non. Préallouer un fichier (comme fallocate) alloue des blocs à ce fichier. Le refreservation est une garantie au niveau dataset qui réduit ce que les autres datasets peuvent utiliser. C’est une politique, pas un agencement d’allocation spécifique.
7) How do snapshots interact with refreservation?
Les snapshots consomment de l’espace du pool au fur et à mesure que le dataset live change. Le refreservation ne « réserve » pas l’espace des snapshots, mais il aide à garantir que les données live du dataset disposent d’une marge protégée pour croître.
8) How do I pick a refreservation size?
Basez-le sur : débit d’écriture maximum × (temps de détection + temps de mitigation) plus une marge pour le slop opérationnel. Si votre WAL peut croître de 30G en une heure pendant une tempête de replay, réserver 10G est de l’optimisme, pas de l’ingénierie.
9) Can I set refreservation on a zvol?
Oui, et cela peut être particulièrement pertinent pour des disques VM backés par zvol où vous souhaitez garantir de l’espace backend. Mais considérez aussi volsize et si vous faites effectivement du thin provisioning.
Conclusion
Le refreservation ZFS n’est pas un code cheat pour la capacité. C’est un outil de conception des modes de défaillance. Dans un pool partagé, quelque chose finira par essayer de manger tout l’espace disponible — logs, artefacts, une requête runaway, une exportation « temporaire ». Sans garanties, la mauvaise chose échoue en premier, et l’incident devient un problème business.
Utilisez le refreservation pour garder les datasets qui doivent continuer d’écrire. Associez-le aux quotas pour contenir les datasets qui ne doivent pas vous ruiner la journée. Et souvenez-vous de la vérité ZFS la plus utile opérationnellement : quand les calculs d’espace deviennent étranges, c’est presque toujours des snapshots, des reservations, ou les deux — et ZFS vous dira lesquels, si vous lui demandez correctement.