Quota ZFS vs réservation : le duo de contrôle d’espace à maîtriser

Cet article vous a aidé ?

ZFS vous offre deux réglages pour contrôler l’espace qui se ressemblent, sonnent pareil, et se comportent juste assez différemment pour causer des incidents en production : quota et réservation. L’un est un plafond. L’autre est un plancher. Et les deux sont appliqués par la comptabilité interne de ZFS — pas par ce que du pense, pas par ce que votre application « ressent », et certainement pas par la présentation de votre budget de stockage.

Si vous exploitez des systèmes multi-tenant, des builders CI, des fermes de VM, des flottes de bases de données, ou tout ce qui peut « finir par remplir le pool », quota et réservation font la différence entre une astreinte calme et une salle de crise à 02:00. Cet article est écrit comme vous opérez réellement ZFS : avec des commandes, des symptômes, et la réalité désordonnée des snapshots, de refquota, et du « pourquoi il n’y a pas d’espace alors que df le dit ? »

1. Quota vs réservation : les vraies définitions

Quota : « Vous ne pouvez pas dépasser ceci. »

Un quota sur un dataset est un plafond strict sur la quantité d’espace que ce dataset (et ses descendants) sont autorisés à consommer. Une fois que l’utilisation du dataset atteint le quota, les écritures nécessitant plus d’espace échouent avec ENOSPC (ou des variantes spécifiques à l’application de « plus d’espace »).

Comportement clé : ZFS applique le quota en se basant sur sa comptabilité interne de l’espace référencé logique (avec des nuances à respecter, en particulier une fois que des snapshots existent). Un quota n’est pas de l’espace « réservé ». C’est la permission de consommer jusqu’à une limite.

Réservation : « Tant d’espace m’appartient même si tout le monde a faim. »

Une réservation est une garantie : ZFS mettra de côté de l’espace du pool pour qu’un dataset puisse continuer à écrire jusqu’à ce montant réservé, même si d’autres datasets se battent pour l’espace libre.

Comportement clé : les réservations réduisent immédiatement l’espace disponible du pool pour les autres, même si le dataset n’utilise pas actuellement cet espace. C’est la garantie « plancher ».

Deux phrases pour garder la tête froide

  • Le quota est une limite de vitesse. Vous pouvez rouler jusqu’à cette limite, mais ça ne vous achète pas de carburant.
  • La réservation est un bon pour du carburant. Elle ne vous dit pas où aller, mais garantit que vous pouvez aller quelque part.

Blague n°1 (courte et pertinente) : Un quota, c’est le CFO qui dit « ne dépensez pas plus que ça ». Une réservation, c’est le CFO qui met réellement l’argent dans votre centre de coût — rare, magnifique, et toujours un peu déroutant.

2. Le modèle mental : plafond, plancher, et qui paie

La plupart des équipes posent correctement les quotas le premier jour : « Chaque locataire reçoit 500G. » Puis survient le premier incident parce que le quota ne protège pas le pool. Il protège seulement les autres datasets contre la croissance de ce dataset. Si vous attribuez des quotas qui totalisent 200 % de la capacité du pool (surcommit), vous jouez sur le comportement. Parfois c’est acceptable. Parfois c’est ainsi que l’on découvre le sens de « write amplification pendant la compaction ».

Les réservations sont le mode d’échec opposé : elles protègent le dataset, mais peuvent affamer silencieusement tout le reste. Une réservation, c’est comme entrer dans un frigo partagé et mettre votre nom sur la moitié des étagères « au cas où ».

Pensez en trois nombres, pas un seul

Quand vous déboguez l’espace, vous avez besoin de trois concepts distincts :

  • Utilisé : ce que ZFS compte comme utilisé par les datasets et les snapshots.
  • Disponible : ce que ZFS dit pouvoir être alloué (après l’espace de slop, les réservations, etc.).
  • Référencé vs logique vs physique : combien de données sont « à vous », combien sont partagées par des snapshots, et combien sont réellement sur disque après compression.

Les quotas et réservations s’appliquent à la frontière du dataset

Les datasets ZFS sont l’unité d’application. Les quotas/réservations ne s’appliquent pas à « un répertoire » sauf si vous utilisez des project quotas (plus loin). Pour les zvols VM, il existe d’autres réglages (volsize, refreservation) et la confusion augmente.

Que bloque-t-on quand on atteint un quota ?

Les écritures qui nécessitent de nouveaux blocs. Les réécritures peuvent aussi nécessiter de nouveaux blocs car ZFS est copy-on-write. Cela signifie que « j’édite un fichier en place » peut toujours allouer, et les quotas peuvent toujours mordre.

Que se passe-t-il quand le pool est plein mais que vous avez une réservation ?

Si un dataset a une réservation et que le pool devient tendu, ZFS essaie de préserver ce montant réservé pour le dataset. Cela peut signifier que d’autres datasets voient ENOSPC plus tôt que prévu, car, de leur point de vue, l’espace réservé n’a jamais été vraiment « disponible ».

3. Faits intéressants et contexte historique

Les ingénieurs stockage aiment le « simple ». ZFS aime le « correct ». L’écart entre ces deux approches est l’endroit où vivent quotas et réservations. Voici quelques points de contexte qui aident à expliquer pourquoi le système se comporte ainsi :

  1. ZFS a été conçu autour du copy-on-write, ce qui signifie que les réécritures allouent de nouveaux blocs. La comptabilité d’espace doit considérer les blocs « anciens » retenus par les snapshots, pas seulement le système de fichiers en direct.
  2. Les premières versions de ZFS ont mis l’accent sur l’intégrité bout en bout (checksums, auto-réparation) bien avant que ce soit courant ; l’application des quotas devait fonctionner avec une sémantique transactionnelle, pas en « best effort ».
  3. Les concepts de « refquota » et « refreservation » existent parce que les snapshots ont compliqué l’idée naïve de « un dataset utilise X ». L’espace référencé et l’espace total sont des factures différentes.
  4. Il existe un « slop space » dans ZFS (une petite réserve non allouable au niveau du pool) pour maintenir le système fonctionnel quand il est presque plein. Cela rend « pourquoi il manque 5G ? » un mystère récurrent pour les débutants.
  5. La compression change la perception humaine de l’utilisation : un quota est appliqué sur la comptabilité logique, tandis que la consommation physique peut être plus faible. Les utilisateurs n’aiment pas qu’on leur dise « vous êtes à court d’espace » quand les disques ne sont pas pleins.
  6. Le provisionnement thin est devenu courant, et ZFS l’a adopté avec les datasets et quotas — mais les réservations sont le contrepoids quand vous avez besoin de marge garantie.
  7. Le stockage de VM a popularisé les zvols, et beaucoup d’erreurs opérationnelles viennent du fait de traiter les zvols comme des systèmes de fichiers. volsize n’est pas un quota ; c’est la taille de l’appareil.
  8. La containerisation a rendu la disposition multi-tenant normale. Les datasets ZFS sont devenus une frontière propre pour les quotas et la délégation, mais seulement si vous comprenez les descendants et le comportement des snapshots.
  9. Les project quotas sont apparus pour répondre à « j’ai besoin de limites par répertoire » sans exploser le nombre de datasets. Ils sont puissants, mais ajoutent une couche de comptabilité qu’il faut surveiller.

4. Les propriétés que vous utiliserez réellement (et leurs pièges)

ZFS expose une petite constellation de propriétés de contrôle d’espace. Apprenez-les par paires, car c’est ainsi qu’elles se comportent en pratique.

quota et reservation : s’appliquent au dataset + descendants

quota limite l’espace total consommé par un dataset et tous ses enfants. Même histoire pour reservation : il réserve pour le dataset et ses descendants.

Cela fonctionne bien quand vous allouez « un locataire » comme dataset de haut niveau et placez tout en dessous. Ce n’est pas idéal quand vous voulez plafonner seulement le dataset parent mais que quelqu’un crée ensuite des enfants et se demande pourquoi le quota du parent « ne fait rien ». Il fait exactement ce qu’il promet : gouverner tout l’arbre.

refquota et refreservation : s’appliquent uniquement au dataset (pas aux descendants, pas aux snapshots)

refquota est un quota sur l’espace référencé du dataset — typiquement signifiant les « données en direct », n’incluant pas les snapshots et pas les descendants. C’est le réglage « je veux limiter ce que ce dataset référence lui-même ».

refreservation est le plancher correspondant pour l’espace référencé.

Opérationnellement, refquota est la façon d’empêcher les workflows lourds en snapshots de punir des locataires pour une histoire qu’ils n’ont pas demandée (ou de vous punir parce que vous conservez sept jours d’historique).

Pourquoi « inclure les snapshots » et « exclure les snapshots » compte

L’espace des snapshots est de l’espace « réel » dans le pool, mais il n’est pas nécessairement « possédé » comme vos locataires l’imaginent. Un dataset peut être à son quota tout en devant allouer de l’espace à cause du churn copy-on-write, surtout quand des snapshots épinglent des blocs anciens. C’est ainsi que vous obtenez le classique : « J’ai supprimé des fichiers mais l’utilisation n’a pas baissé. » Vous n’avez pas supprimé les blocs ; vous avez supprimé des références. Les snapshots ont gardé les anciennes références vivantes.

Les réservations peuvent être supérieures à l’espace utilisé (et c’est le but)

Quand vous définissez une réservation, vous pré-allouez de la disponibilité du pool, vous n’écrivez pas des zéros. Si vous réservez 200G et n’utilisez que 20G, le pool agira toujours comme si ces 200G n’étaient pas disponibles pour les autres datasets. C’est volontaire. C’est aussi une cause fréquente de « faible espace libre mystérieux ».

Délégation et réalité multi-tenant

En entreprise, il est courant de déléguer la gestion des datasets aux équipes plateformes ou même aux locataires (équipes CI, ops serveurs de jeu, etc.). Si vous laissez les locataires créer des snapshots, ils peuvent rendre l’application des quotas injuste à moins de choisir correctement refquota. Et si vous laissez les locataires définir des réservations, vous leur permettez de préempter la capacité du pool. Ce n’est pas un problème technique. C’est un problème d’organigramme.

5. Snapshots : la troisième partie dans chaque dispute

Les snapshots sont la raison pour laquelle ZFS est une joie — et la raison pour laquelle les conversations sur l’espace deviennent étranges.

Les snapshots ne « prennent pas d’espace » à la création, mais ils peuvent le garder indéfiniment

Un snapshot est initialement de la métadonnée. Le coût en espace vient plus tard, quand le dataset en direct change et que le snapshot conserve des références à d’anciens blocs. Supprimer 100G de fichiers du dataset en direct ne libère pas ces blocs si des snapshots les référencent encore.

Comment les snapshots interagissent avec les quotas

Voici la nuance qui fait trébucher les gens : selon le type de quota utilisé, les snapshots peuvent ou non compter dans le quota.

  • quota compte le dataset et ses descendants ; l’espace retenu par les snapshots peut néanmoins provoquer des échecs d’allocation parce que le dataset ne peut pas allouer de nouveaux blocs sans dépasser le quota.
  • refquota se concentre sur l’espace référencé (données en direct). L’espace des snapshots n’est pas « référencé » par le dataset de la même manière, donc c’est mieux quand vous gérez les politiques de snapshot centralement.

Le churn des snapshots rend les quotas « collants »

En pratique, la sensation de collant est le copy-on-write plus la rétention. Les bases de données qui réécrivent de gros fichiers, les jobs de compaction, les images VM, les caches de build — ce sont tous des workloads de « churn » d’espace. Ils peuvent nécessiter un double espace temporaire pendant une réécriture. Si vous fixez les quotas trop près de l’utilisation en régime permanent, vous créez un système qui fonctionne… jusqu’à ce qu’il doive faire de la maintenance.

Blague n°2 (courte et pertinente) : Les snapshots, c’est comme prendre des photos de votre armoire. Supprimer les chaussettes plus tard ne rend pas les photos plus petites, et ZFS n’est pas impressionné par votre nouvel esprit minimaliste.

6. Trois mini-récits du monde corporate

Mini-récit 1 : L’incident causé par une mauvaise hypothèse (le quota comme filet de sécurité du pool)

L’équipe plateforme gérait un pool ZFS partagé pour des runners CI. Chaque projet avait son propre dataset sous tank/ci, et chaque dataset avait un quota. Tout le monde se sentait responsable. Tout le monde se sentait en sécurité. Le pool était dimensionné pour la charge typique et les builds « en rafale », et les quotas étaient censés empêcher qu’une équipe ne parte en vrille.

Puis un gros refactor est arrivé dans un monorepo, et une nouvelle étape de build a commencé à produire des artefacts en double : une fois non compressé, une fois compressé, puis upload des deux. Le quota du dataset empêchait une croissance infinie, d’accord — mais le build avait encore assez de marge pour s’étendre rapidement sur de nombreux projets à la fois. Les quotas n’ont pas empêché le pool de se remplir parce que le pool est partagé et que la somme des « croissances autorisées » dépassait largement la capacité réelle.

À peu près au même moment, des snapshots étaient pris toutes les 15 minutes pour des « rollback rapides » des images de runners. Personne n’avait relié cette politique aux artefacts CI. Le churn d’écriture plus des snapshots fréquents ont créé beaucoup de blocs épinglés. Les répertoires de build étaient supprimés après l’exécution, mais les snapshots maintenaient le churn jusqu’à l’expiration de la rétention.

L’incident n’a pas été dramatique au début. Ça a commencé par des builds instables. Puis ce sont devenues des erreurs d’extraction de paquets. Puis quelques hosts de runners sont passés en lecture seule de manière étrange parce que les applications se comportaient mal sous ENOSPC. La première réaction de l’équipe a été d’augmenter les quotas, parce que « les projets atteignent le quota ». Ça a fait remplir le pool plus vite.

La correction finale a été ennuyeuse et correcte : définir une politique au niveau du pool (surveiller l’espace libre du pool), déplacer les artefacts CI vers un dataset avec rétention de snapshots courte (ou pas de snapshots), et garder les quotas pour l’équité entre locataires — pas pour la protection du pool. Ils ont aussi introduit une petite réservation pour les datasets système (logs, caches de paquets) afin que les hosts puissent encore fonctionner en cas d’urgence.

Mini-récit 2 : L’optimisation qui a mal tourné (réservations partout « pour la fiabilité »)

Un ingénieur orienté stockage a rejoint une équipe qui avait été brûlée par des pannes « pool full ». Son instinct était raisonnable : garantir de la capacité pour les datasets critiques. Il a créé des réservations pour les bases de données, les logs, et une poignée de services qui « ne doivent jamais échouer ». L’idée était d’éviter les voisins bruyants et le comportement redouté d’un pool presque plein.

Ça a fonctionné un temps. Puis la croissance est arrivée. De nouveaux services sont apparus. Chacun a demandé « juste une petite réservation » parce que ça paraissait responsable. Personne ne voulait être le service qui n’avait pas réservé d’espace et qui provoquerait ensuite une panne. C’est comme cela que de bonnes intentions se transforment en mauvais calculs.

Après un trimestre, le pool semblait à moitié vide en utilisation brute, mais le « disponible » était bas. Les équipes continuaient d’ouvrir des tickets : « df montre de l’espace libre mais les écritures échouent. » Ils n’avaient pas tort ; ils regardaient juste la mauvaise couche de comptabilité. Les réservations avaient silencieusement pré-engagé la majeure partie du pool.

Le retour de bâton a été opérationnel : lors d’un pic de trafic, la pipeline de logs a eu besoin d’une croissance temporaire et n’a pas pu l’obtenir. Les données n’étaient pas volumineuses à long terme, mais le pic nécessitait de la capacité d’explosion. Le pool avait de l’espace physique ; il n’avait pas d’espace allouable parce qu’il avait été réservé. Le résultat a été des logs perdus au moment où le debug était le plus nécessaire.

Le postmortem a conclu avec une règle : les réservations sont pour la survivabilité de l’infrastructure (datasets OS, caches de paquets critiques, tête de DB WAL) et pour les workloads avec SLA strict. Tout le reste reçoit des quotas et de la surveillance. L’équipe a aussi appris à documenter les réservations comme une « dette de capacité » qui doit être payée avec des disques réels.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise (refquota + frontières de snapshot)

Une entreprise exploitait une plateforme d’analytics multi-tenant. Les locataires uploadaient des données, des jobs les traitaient, et les résultats étaient stockés par locataire. L’équipe plateforme voulait deux choses : des limites prédictibles par locataire et un rollback fiable pour la sécurité opérationnelle. Ils savaient aussi que les snapshots seraient non négociables parce que des « oups » arrivent chaque semaine dans les systèmes de données.

Au lieu d’utiliser quota partout, ils ont utilisé un modèle : les datasets locataires recevaient un refquota pour appliquer les limites sur les données en direct. Les snapshots étaient gérés centralement par l’équipe plateforme, avec des politiques de rétention adaptées aux workloads (courte pour le scratch, plus longue pour les résultats validés).

Ils ont créé un sous-arbre de datasets séparé pour les données scratch/intermédiaires, avec un élagage agressif des snapshots et un tuning recordsize approprié. Surtout, ils ont aligné les frontières de snapshot avec la propriété : les locataires n’étaient pas facturés (via quota) pour l’historique de sécurité géré par la plateforme, et les datasets scratch n’étaient pas autorisés à conserver des snapshots au-delà d’une courte fenêtre.

Des mois plus tard, un mauvais déploiement a déclenché une vague de retries de jobs qui ont réécrit massivement des fichiers intermédiaires. Le churn était réel. Mais le système est resté opérationnel parce que : (1) les datasets scratch avaient une rétention de snapshots qui ne pinnaient pas le churn longtemps, et (2) une petite réservation existait pour les datasets critiques système afin que les logs et services centraux puissent continuer à écrire pendant que l’équipe stabilisait les jobs.

Pas d’héroïsme. Pas de « magie du stockage ». Juste des frontières propres, une application conservatrice des règles, et l’humilité d’assumer que quelqu’un fera forcément quelque chose de stupide avec le disque.

7. Tâches pratiques : commandes et interprétation (12+)

Voici les commandes que j’utilise réellement quand un pool est tendu, un dataset atteint des limites, ou que quelqu’un affirme « ZFS ment ». Les commandes sont montrées avec des sorties typiques. Adaptez les noms de pool/dataset à votre environnement.

Tâche 1 : Lister la capacité et la santé du pool

cr0x@server:~$ zpool list
NAME   SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  7.25T  5.61T  1.64T        -         -    22%    77%  1.00x  ONLINE  -

Interprétation : Le pool est rempli à 77%. Ce n’est pas une urgence en soi, mais si ça grimpe dans les 80–90 %, les allocations deviennent fragiles (et les performances peuvent vaciller). Cette sortie ne montre pas directement les réservations.

Tâche 2 : Vérifier l’espace « available » du pool en tenant compte du slop

cr0x@server:~$ zfs get -H -o name,property,value available tank
tank	available	1.52T

Interprétation : ZFS peut rapporter moins que FREE à cause du slop et d’autres comptabilités. Si zpool list montre du free mais que zfs get available est bas, vous entrez dans la zone où ENOSPC apparaît « tôt ».

Tâche 3 : Afficher quotas et réservations sur un arbre de datasets

cr0x@server:~$ zfs get -r -o name,property,value -s local quota,reservation,refquota,refreservation tank/tenants
NAME                  PROPERTY        VALUE
tank/tenants          quota           -
tank/tenants          reservation     -
tank/tenants          refquota        -
tank/tenants          refreservation  -
tank/tenants/acme     quota           2T
tank/tenants/acme     reservation     -
tank/tenants/acme     refquota        1.5T
tank/tenants/acme     refreservation  200G
tank/tenants/zephyr   quota           1T
tank/tenants/zephyr   reservation     -
tank/tenants/zephyr   refquota        -
tank/tenants/zephyr   refreservation  -

Interprétation : Ceci vous dit qui a des limites et des garanties. Notez le mélange : quota plafonne tout le sous-arbre ; refquota plafonne les données en direct pour ce dataset seulement ; refreservation garantit de la marge pour les données référencées.

Tâche 4 : Trouver rapidement les plus gros datasets

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint -S used | head -n 12
NAME                 USED  AVAIL  REFER  MOUNTPOINT
tank                 5.61T 1.52T   128K  /tank
tank/tenants         4.90T 1.52T    96K  /tank/tenants
tank/tenants/acme    1.92T  800G  1.44T  /tank/tenants/acme
tank/tenants/zephyr  1.31T 1.52T  1.05T  /tank/tenants/zephyr
tank/vm              420G  1.52T    96K  /tank/vm
tank/logs            180G  1.52T   160G  /tank/logs

Interprétation : USED inclut les snapshots et les descendants. REFER est les « données en direct » référencées par ce dataset. Quand USED est bien plus grand que REFER, ce sont généralement les snapshots/enfants la raison.

Tâche 5 : Identifier les datasets riches en snapshots (écart USED vs REFER)

cr0x@server:~$ zfs list -t filesystem -o name,used,refer -S used | head -n 10
NAME                 USED  REFER
tank/tenants/acme    1.92T 1.44T
tank/tenants/zephyr  1.31T 1.05T
tank/logs            180G  160G
tank/ci              140G   18G
tank/home            110G   45G

Interprétation : tank/ci est un signal d’alerte : 140G used, seulement 18G référencé. C’est généralement des snapshots qui retiennent le churn, ou beaucoup de datasets enfants.

Tâche 6 : Inspecter les snapshots et leur espace

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -S used | head -n 8
NAME                                   USED  REFER  CREATION
tank/ci@autosnap_2025-12-24_0100        22.4G    0B  Wed Dec 24 01:00 2025
tank/ci@autosnap_2025-12-24_0045        18.1G    0B  Wed Dec 24 00:45 2025
tank/tenants/acme@daily_2025-12-23      12.7G    0B  Tue Dec 23 02:00 2025
tank/home@hourly_2025-12-24_0100         6.2G    0B  Wed Dec 24 01:00 2025

Interprétation : USED d’un snapshot est l’espace unique détenu par ce snapshot (l’espace qui serait libéré si vous le détruisiez, en supposant qu’aucun autre snapshot ne référence ces blocs). Une série de snapshots volumineux indique du churn.

Tâche 7 : Montrer la répartition d’espace pour un dataset

cr0x@server:~$ zfs get -o property,value -p used,usedbysnapshots,usedbydataset,usedbychildren,usedbyrefreservation tank/ci
PROPERTY             VALUE
used                 150323855360
usedbysnapshots      126406688768
usedbydataset        19327352832
usedbychildren       0
usedbyrefreservation 0

Interprétation : Les snapshots consomment ~126G d’espace unique. C’est là que votre pool est parti.

Tâche 8 : Définir un quota (plafond) sur un dataset

cr0x@server:~$ sudo zfs set quota=500G tank/tenants/zephyr
cr0x@server:~$ zfs get -H -o name,property,value quota tank/tenants/zephyr
tank/tenants/zephyr	quota	500G

Interprétation : zephyr (et tous ses enfants) ne peuvent pas consommer plus de 500G au total. S’il est déjà au-dessus de 500G, les écritures échoueront jusqu’à ce que l’utilisation baisse.

Tâche 9 : Définir une réservation (garantie) pour une marge critique

cr0x@server:~$ sudo zfs set reservation=50G tank/logs
cr0x@server:~$ zfs get -H -o name,property,value reservation tank/logs
tank/logs	reservation	50G

Interprétation : 50G est retiré de l’« available » pour les autres et réservé pour tank/logs (et ses descendants). Cela aide les logs à continuer d’écrire lorsque le pool est sous pression.

Tâche 10 : Utiliser refquota pour limiter uniquement les données en direct (limites locataire sûres pour les snapshots)

cr0x@server:~$ sudo zfs set refquota=300G tank/tenants/acme
cr0x@server:~$ zfs get -H -o name,property,value refquota tank/tenants/acme
tank/tenants/acme	refquota	300G

Interprétation : Cela plafonne les données référencées en direct d’acme. Si les snapshots de la plateforme gonflent USED, refquota a moins de chances de punir le locataire pour la politique de rétention.

Tâche 11 : Utiliser refreservation pour garantir une marge d’écriture en direct

cr0x@server:~$ sudo zfs set refreservation=20G tank/tenants/acme
cr0x@server:~$ zfs get -H -o name,property,value refreservation tank/tenants/acme
tank/tenants/acme	refreservation	20G

Interprétation : Garantit 20G d’espace référencé pour les écritures propres à ce dataset. Utile pour des choses comme le WAL de base de données ou le scratch qui ne doivent pas se bloquer sous pression du pool.

Tâche 12 : Confirmer pourquoi un dataset montre un faible « avail » (pression quota/réservation)

cr0x@server:~$ zfs get -o name,quota,refquota,reservation,refreservation,used,avail,refer tank/tenants/acme
NAME               QUOTA  REFQUOTA  RESERV  REFRESERV  USED  AVAIL  REFER
tank/tenants/acme     2T     300G       -      20G   1.92T  0B   1.44T

Interprétation : AVAIL 0B est clé. Cela signifie que du point de vue de ZFS ce dataset ne peut pas allouer plus d’espace, probablement à cause d’un refquota appliqué inférieur au REFER actuel. En d’autres termes : les limites sont incohérentes avec la réalité ; vous venez de mettre la ceinture après l’accident.

Tâche 13 : Réduire la pression des snapshots en supprimant les anciens snapshots (avec précaution)

cr0x@server:~$ zfs list -t snapshot -o name,used -S used | grep '^tank/ci@' | head
tank/ci@autosnap_2025-12-24_0100   22.4G
tank/ci@autosnap_2025-12-24_0045   18.1G
tank/ci@autosnap_2025-12-24_0030   15.9G
cr0x@server:~$ sudo zfs destroy tank/ci@autosnap_2025-12-24_0030

Interprétation : Détruire un snapshot libère de l’espace seulement si les blocs sont uniques à celui-ci. Confirmez toujours les politiques et les dépendances de réplication avant de détruire des snapshots en production.

Tâche 14 : Révéler les gouffres d’espace cachés avec « written » (churn récent)

cr0x@server:~$ zfs get -H -o name,property,value written@autosnap_2025-12-24_0045 tank/ci
tank/ci	written@autosnap_2025-12-24_0045	41234597888

Interprétation : Cela montre les octets écrits depuis ce snapshot. Des valeurs élevées + des snapshots fréquents forment une recette pour une croissance due aux snapshots.

Tâche 15 : Comparer la comptabilité ZFS à la vue du système de fichiers

cr0x@server:~$ df -h /tank/ci
Filesystem      Size  Used Avail Use% Mounted on
tank/ci         1.6T   19G  0B  100% /tank/ci

Interprétation : Le mount montre 0B disponible parce que ZFS applique la disponibilité du dataset après quotas/réservations. Si les utilisateurs disent « df indique plein », croyez-les, puis regardez les propriétés ZFS pour comprendre pourquoi.

Tâche 16 : Trouver les réservations qui « volent » la disponibilité du pool

cr0x@server:~$ zfs get -r -H -o name,property,value reservation,refreservation tank | egrep -v '\t-\s*$' | head -n 20
tank/logs	reservation	50G
tank/system	reservation	30G
tank/tenants/acme	refreservation	20G

Interprétation : Toute valeur non-- réduit l’espace allouable du pool. Si l’« available » semble bas, cette liste en est souvent la raison.

8. Playbook de diagnostic rapide

Voici la séquence de triage qui vous amène rapidement à la cause racine quand quelqu’un signale « dataset plein », « pool plein », ou « écritures échouent ». L’objectif est d’éviter la boucle classique d’augmenter les quotas à l’aveugle ou de supprimer des données au hasard sous pression.

Étape 1 : Est-ce le pool, le dataset ou une limite ?

cr0x@server:~$ zpool list tank
NAME   SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank  7.25T  6.98T   270G        -         -    29%    96%  1.00x  ONLINE  -
cr0x@server:~$ zfs get -H -o name,property,value available tank
tank	available	120G

Interprétation : Si CAP du pool est >90% et que tank available est bas, vous avez un événement de capacité pool. Si le pool a l’air correct mais qu’un dataset est à sec, c’est généralement des quotas, des réservations, ou des snapshots qui épinglent l’espace.

Étape 2 : Identifier quel dataset est contraint

cr0x@server:~$ zfs list -o name,used,avail,refer -S used | head -n 15
NAME                 USED  AVAIL  REFER
tank                 6.98T  120G   128K
tank/tenants         5.80T  120G    96K
tank/tenants/acme    2.40T    0B  1.90T
tank/tenants/zephyr  1.70T  120G  1.65T
tank/ci              650G     0B   40G

Interprétation : Les datasets avec AVAIL 0B sont ceux où les applications échoueront en premier.

Étape 3 : Vérifier s’il s’agit de quotas/réservations ou de snapshots

cr0x@server:~$ zfs get -o name,quota,refquota,reservation,refreservation,used,usedbysnapshots,refer,avail tank/ci
NAME     QUOTA  REFQUOTA  RESERV  REFRESERV  USED  USEDBYSNAPSHOTS  REFER  AVAIL
tank/ci  200G   -         -       -          650G  590G             40G    0B

Interprétation : Ici, le quota est de 200G mais le dataset utilise 650G (probablement à cause de descendants ou de snapshots ; possible aussi que le quota ait été appliqué plus tard ou au mauvais niveau). USEDBYSNAPSHOTS est énorme, donc les snapshots sont le levier immédiat.

Étape 4 : Décider du remède approprié pour le moment

  • Urgence pool plein : détruisez d’abord les snapshots « les plus sûrs » à supprimer (ceux avec le plus grand USED), ou taillez la rétention. Évitez le « rm -rf » à moins de comprendre que ce sont les snapshots qui retiennent l’espace de toute façon.
  • Locataire atteignant son quota : décidez d’augmenter le quota ou de réduire l’utilisation ; vérifiez si la rétention des snapshots provoque une croissance « invisible ».
  • Tout le monde est affamé mais le pool n’est pas plein : auditez les reservations/refreservations et annulez le sur-engagement des garanties.

9. Erreurs courantes, symptômes et correctifs

Erreur 1 : Considérer le quota comme « protection du pool »

Symptôme : Le pool se remplit même si chaque dataset a un quota. Plusieurs locataires atteignent leur quota simultanément pendant un événement de churn.

Pourquoi ça arrive : Les quotas plafonnent les individus, pas la somme. Si vous sur-engagez les quotas, le pool peut encore se remplir quand tout le monde croît en même temps.

Correctif : Surveillez l’espace libre du pool et fixez des garde-fous opérationnels (alertes à 80/85/90 %). N’utilisez les réservations que pour les datasets critiques. Gardez les quotas pour l’équité, pas pour la sécurité.

Erreur 2 : Mettre des réservations « au cas où » partout

Symptôme : Le pool semble avoir de l’espace libre, mais de nombreux datasets montrent un faible AVAIL ou les écritures échouent de façon imprévisible. Les équipes voient des chiffres contradictoires entre les outils.

Pourquoi ça arrive : Les réservations pré-consomment l’espace allouable du pool. Trop de réservations rendent le pool fonctionnellement plein même s’il n’est pas physiquement plein.

Correctif : Listez les réservations récursivement, justifiez chacune, et supprimez/redimensionnez-les. Préférez refreservation pour une marge ciblée plutôt que des réservations larges sur les sous-arbres.

Erreur 3 : Utiliser quota quand vous vouliez refquota (les snapshots rendent ça douloureux)

Symptôme : Les locataires se plaignent que l’espace n’a pas baissé après des suppressions ; ils atteignent le quota malgré le « nettoyage ».

Pourquoi ça arrive : Les snapshots retiennent d’anciens blocs. quota ne sépare pas les données en direct de l’historique des snapshots comme les locataires s’y attendent.

Correctif : Utilisez refquota pour les limites locataires si les snapshots sont gérés centralement. Ou déplacez la prise de snapshots vers un dataset parent et laissez les datasets locataires sans snapshots, selon votre modèle de gouvernance.

Erreur 4 : Appliquer le quota au mauvais niveau de l’arbre de datasets

Symptôme : Un quota « ne fait rien » ou a une portée surprenante. Un dataset enfant remplit le quota du parent de manière inattendue.

Pourquoi ça arrive : quota s’applique au dataset + descendants. Le définir sur le mauvais parent change qui est inclus.

Correctif : Visualisez l’arbre des datasets. Appliquez les quotas à la racine du locataire. Utilisez refquota si vous voulez plafonner uniquement l’usage référencé d’un dataset.

Erreur 5 : Confondre le dimensionnement d’un zvol avec des quotas

Symptôme : Le disque VM « est plein » même si le quota du dataset semble généreux, ou le pool se remplit de façon inattendue à cause d’hypothèses de thin provisioning.

Pourquoi ça arrive : La volsize d’un zvol définit la taille de l’appareil ; l’espace est alloué au fur et à mesure des écritures, et les snapshots peuvent aussi épingler des anciens blocs. Les comportements de quota/réservation peuvent différer selon la façon dont vous provisionnez.

Correctif : Pour les VM sur zvol, suivez l’utilisation des zvols et les politiques de snapshots attentivement. Envisagez refreservation pour les zvols critiques si le sur-engagement est risqué.

Erreur 6 : Définir des quotas trop serrés pour des workloads copy-on-write

Symptôme : La compaction de base de données, les mises à jour d’images VM, ou des étapes de build échouent même si l’utilisation en régime permanent est inférieure au quota.

Pourquoi ça arrive : Les réécritures ont besoin d’allocations temporaires supplémentaires ; les snapshots amplifient cela. Il faut une marge pour les réécritures transactionnelles.

Correctif : Prévoyez de l’espace pour les pics. Utilisez refreservation ou fixez des quotas avec marge. Réduisez la fréquence des snapshots sur les datasets à fort churn.

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

Checklist A : Concevoir le stockage des locataires (le plan « ne me dérangez pas »)

  1. Créez un dataset par locataire (ou par environnement) comme frontière de gestion.
  2. Décidez si les snapshots sont détenus par le locataire ou par la plateforme. Ne partagez pas la propriété par accident.
  3. Si les snapshots sont gérés par la plateforme, préférez refquota pour les limites locataires.
  4. Définissez quota uniquement quand vous voulez explicitement inclure les enfants (commun pour la « racine locataire »).
  5. Ajoutez une petite reservation ou refreservation seulement pour les workloads qui doivent continuer à écrire sous pression du pool.
  6. Alarmez sur la capacité du pool, pas seulement sur l’utilisation des datasets. Les quotas ne vous sauvent pas d’une croissance agrégée.
  7. Documentez : quels datasets sont autorisés à avoir des réservations, et pourquoi.

Checklist B : Répondre à « plus d’espace » en production

  1. Vérifiez la capacité du pool : zpool list.
  2. Vérifiez l’espace allouable du pool : zfs get available tank.
  3. Trouvez les datasets à AVAIL 0B : zfs list -o name,used,avail,refer -S used.
  4. Pour le dataset affecté, inspectez limites et utilisation des snapshots : zfs get usedbysnapshots,quota,refquota,reservation,refreservation.
  5. Si les snapshots sont en cause, supprimez/élaguez les snapshots selon la politique ; n’espérez pas que « rm » fasse des miracles.
  6. Si des réservations affament le pool, réduisez/supprimez les réservations non critiques.
  7. Ce n’est qu’ensuite que vous pouvez envisager d’augmenter les quotas (et traitez cela comme de la planification de capacité, pas comme un correctif rapide).

Checklist C : Hygiène trimestrielle (la pratique ennuyeuse qui fonctionne)

  1. Inventoriez tous les quota/refquota/reservation/refreservation non par défaut.
  2. Confirmez que les réservations correspondent toujours à la criticité et aux projections de croissance.
  3. Revue des politiques de snapshot sur les datasets à fort churn (CI, scratch, DB temporaires).
  4. Repérez les datasets où USED est bien supérieur à REFER ; enquêtez sur les raisons.
  5. Vérifiez la surveillance : alertes sur la capacité du pool, alertes de croissance des snapshots, et « datasets avec AVAIL proche de zéro ».

11. FAQ

Q1 : Si je définis un quota, ZFS « alloue »-t-il cet espace ?

Non. Un quota est une limite, pas une pré-allocation. D’autres datasets peuvent consommer le pool jusqu’à ce que le dataset lié au quota tente d’écrire et découvre que le pool (ou son quota) ne le permet pas.

Q2 : Si je définis une réservation, ZFS écrit-il des zéros sur le disque ?

Non. Elle réserve de l’espace allouable dans la comptabilité du pool. C’est une promesse, pas un pré-remplissage. L’espace « available » du pool pour les autres diminue immédiatement, toutefois.

Q3 : Dois-je utiliser quota ou refquota pour les locataires ?

Si les locataires doivent être responsables des snapshots et des enfants, utilisez quota. Si les snapshots sont gérés par l’équipe plateforme (ou si vous voulez que les limites locataires reflètent surtout les données en direct), utilisez refquota. La bonne réponse dépend autant de la propriété et des attentes que des octets.

Q4 : Pourquoi la suppression de fichiers n’a-t-elle pas libéré d’espace ?

Parce que des snapshots (ou des clones) référencent encore les anciens blocs. Vérifiez usedbysnapshots et listez les snapshots par USED. L’espace est libéré quand la dernière référence est détruite, pas quand un fichier disparaît de la vue en direct.

Q5 : Pourquoi df est-il en désaccord avec zpool list ?

df rapporte la disponibilité au niveau du dataset après quotas/réservations. zpool list rapporte l’allocation brute au niveau du pool. Les deux ont raison, ils répondent juste à des questions différentes. Lorsqu’ils divergent, regardez les quotas, les réservations et le slop.

Q6 : Les réservations peuvent-elles causer une panne ?

Oui — en affamant les workloads non réservés même quand de l’espace physique existe. Les réservations sont puissantes et doivent être traitées comme des engagements de capacité. Si vous ne signeriez pas cela comme un contrat, ne le définissez pas comme réservation.

Q7 : Les quotas tiennent-ils compte de la compression ?

Les quotas sont basés sur la comptabilité logique de ZFS, pas sur « combien de secteurs disque ont été utilisés après compression » comme les utilisateurs s’y attendent. La compression peut rendre l’utilisation physique plus faible, mais les quotas peuvent encore être atteints sur la base de l’espace référencé logique. C’est bon pour la prévisibilité, agaçant à expliquer.

Q8 : Quel est le modèle le plus simple et sûr pour les datasets système critiques ?

Donnez aux datasets système (logs, services centraux) une réservation modeste pour que le système d’exploitation puisse continuer à écrire lors d’un événement de pression du pool. Gardez la réservation petite, révisée et justifiée — suffisante pour la survie en incident, pas suffisante pour devenir un sur-engagement silencieux.

Q9 : Si j’ai des réservations, puis-je quand même surcommitter le pool avec des quotas ?

Oui. Les quotas peuvent encore totaliser plus que la capacité restante du pool. Les réservations réduisent ce qui est réellement disponible. Traitez les totaux de quota comme une « demande potentielle », pas comme une « fourniture allouée ».

Q10 : Comment savoir rapidement si les snapshots sont le principal coupable ?

Comparez USED vs REFER pour le dataset, puis vérifiez usedbysnapshots. Si les snapshots dominent, l’élagage des snapshots (selon la politique) libérera généralement le plus d’espace le plus vite.

12. Conclusion

Quota et réservation ne sont pas des fonctionnalités concurrentes. Ils forment un duo : le quota empêche un dataset de prendre trop, et la réservation empêche un dataset d’être chassé. Dans les systèmes de production réels, vous avez typiquement besoin des deux — simplement pas partout, et pas sans comprendre les snapshots.

Si vous retenez une règle opérationnelle : ne discutez pas de « l’espace libre » avant d’avoir vérifié la propre comptabilité de ZFS pour usedbysnapshots, les quotas et les réservations. ZFS ment rarement ; il répond généralement à une question que vous n’aviez pas réalisée.

← Précédent
Hyper-Threading démystifié : threads magiques ou tromperie du planificateur ?
Suivant →
IA sur le CPU : que sont les NPU et pourquoi ils existent

Laisser un commentaire