SSD Nodes Learn 🎉 VPS dès $5.50/mois
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-12

ZFS sur VPS : gérer la consommation RAM de l'ARC

ZFS offre checksum, snapshots et compression, mais son cache ARC peut saturer un VPS. Apprenez à limiter l'usage mémoire pour vos instances de 2 Go ou 4 Go de RAM.

Ce que ZFS vous apporte, et ce qu'il exige

ZFS sur FreeBSD et Linux repose désormais sur une base de code unique, OpenZFS ; les fonctionnalités sont donc identiques sur les deux systèmes. Un serveur utilisant ZFS bénéficie de données vérifiées par checksum, de snapshots instantanés tant que les données ne changent pas, de la réplication avec zfs send, et d'une compression activable par une simple propriété. En contrepartie, il consomme de la mémoire : l'ARC (adaptive replacement cache) accapare par défaut une part importante de la RAM. Sur un VPS (virtual private server) de 2 Go ou 4 Go, cette mémoire est précisément celle dont votre application a besoin.

Ce guide évalue ZFS du point de vue d'un VPS loué avec un ou deux disques virtuels, et non d'une baie de stockage dotée de quarante emplacements. Les fonctionnalités qui conservent leur intérêt dans ce contexte sont celles sur lesquelles vous devez vous concentrer. Il est utile de connaître les limites avant de créer un pool.

OpenZFS sur FreeBSD et Linux : une base de code, deux modes de distribution

FreeBSD intègre ZFS dans son système de base depuis FreeBSD 7.0 en 2008, initialement en tant que fonctionnalité expérimentale. Depuis OpenZFS 2.0 en décembre 2020, FreeBSD et Linux utilisent la même arborescence source. Ainsi, zfs et zpool se comportent de la même manière sur les deux systèmes, et un pool créé sur l'un peut être importé sur l'autre.

La raison pour laquelle ZFS est un paquet sur Linux et fait partie du système de base sur FreeBSD est liée aux licences. OpenZFS est sous licence CDDL (Common Development and Distribution License). Le noyau Linux est sous licence GPL (General Public License) version 2. Le projet du noyau considère ces deux licences comme incompatibles. Par conséquent, le code ZFS n'est pas fusionné dans la branche principale de Linux, et chaque distribution décide de la manière de le distribuer. FreeBSD ne rencontre pas ce conflit, donc ZFS est simplement présent. C'est toute l'histoire pratique : une différence de packaging, sans que vous ayez à prendre parti.

SSD Nodes ne propose pas d'images FreeBSD. Sur un serveur loué ici, c'est donc la partie Linux de ce guide qui s'applique. Si vous utilisez FreeBSD ailleurs, un serveur FreeBSD dispose de ZFS sans module à compiler ni mise à jour du noyau à gérer.

Installation de ZFS et création d'un pool

Sur Ubuntu, le module est inclus dans les paquets du noyau ; vous n'avez donc qu'à installer les commandes.

sudo apt update
sudo apt install -y zfsutils-linux
zfs version

zfs version affiche deux lignes : la version de l'espace utilisateur et celle du module noyau. Si une seule ligne apparaît, le module n'est pas chargé. Le paquet se trouve dans le composant universe, activé par défaut sur les images Ubuntu Server ; si apt ne le trouve pas, exécutez d'abord sudo add-apt-repository universe.

Sur Debian, les paquets se trouvent dans le composant contrib et le module est compilé sur votre machine par DKMS (Dynamic Kernel Module Support). Ajoutez contrib à la ligne Components: dans /etc/apt/sources.list.d/debian.sources, exécutez sudo apt update, puis :

sudo apt install -y linux-headers-$(dpkg --print-architecture) zfs-dkms zfsutils-linux

L'installation compile le module et affiche Building initial module for 6.12.0-..., ce qui prend quelques minutes. Gardez à l'esprit que chaque mise à jour du noyau déclenche une recompilation ; si celle-ci échoue, votre pool ne sera pas importé tant que vous n'aurez pas corrigé le problème.

Sur FreeBSD, rien n'est à installer. Activez le service et démarrez-le.

sysrc zfs_enable=YES
service zfs start

Passons au pool. Examinez d'abord les chemins stables des périphériques, car /dev/vdb est attribué selon l'ordre de détection et peut changer si vous ajoutez un autre volume.

ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tank

zpool status doit afficher state: ONLINE avec votre périphérique listé sous tank. ashift=12 fixe la taille de bloc minimale du pool à 4 KiB, ce qui correspond aux SSD actuels et ne pourra plus être modifié après la création.

La plupart des images louées démarrent sur une partition racine en ext4. ZFS est donc ici utilisé comme pool de données sur un second volume, plutôt que comme système de fichiers racine. Vérifiez que le périphérique est bien celui que vous pensez avant de construire dessus, car confirmer le disque NVMe qui vous a été vendu prend une minute, alors qu'une reconstruction prend une après-midi.

Les sommes de contrôle ne réparent que si le pool possède une redondance

Chaque bloc écrit par ZFS comporte une somme de contrôle, et chaque lecture la vérifie. La détection fonctionne toujours. La réparation nécessite une seconde copie.

Sur un pool à disque unique, ZFS vous indique la vérité et s'arrête là. zpool status -v le signale ainsi :

status: One or more devices has experienced an error resulting in data
        corruption.
action: Restore the file in question if possible.  Otherwise restore the
        entire pool from backup.
errors: Permanent errors have been detected in the following files:

        /tank/data/archive.tar

Le fichier corrompu est identifié. ext4 aurait renvoyé ces octets sans commentaire, c'est donc déjà un avantage. ZFS ne peut toujours pas le corriger, car il n'existe aucune seconde copie dans le pool pour effectuer la réparation.

Avec un miroir, la même lecture est servie depuis le côté sain, le bloc corrompu est réécrit, et l'événement apparaît dans la colonne CKSUM de zpool status. C'est l'auto-guérison, et elle nécessite deux périphériques.

sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2

Sur un VPS, le stockage de l'hôte est généralement déjà redondant, souvent via RAID 10 sous l'hyperviseur. Cela vous protège contre la panne d'un disque. Cela ne vous avertit pas lorsqu'un bloc est corrompu, car la grappe n'a aucun moyen de savoir quelle copie est correcte. ZFS le sait, car il compare les données à une somme de contrôle qu'il a lui-même écrite.

Si vous avez un disque virtuel et souhaitez une capacité de réparation, sudo zfs set copies=2 tank/important stocke deux copies de chaque bloc de ce dataset sur le même disque. Cela double l'espace utilisé par ce dataset, permet de survivre à un bloc corrompu, mais ne sert à rien si le volume entier disparaît.

Un scrub lit tout le contenu du pool et le vérifie.

sudo zpool scrub tank
zpool status tank

Un pool sain se termine par une ligne comme scan: scrub repaired 0B in 00:04:11 with 0 errors. Planifiez cette opération ; une fois par mois est suffisant pour un petit pool.

systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timer

Les datasets sont l'unité de gestion des politiques

Un dataset est un système de fichiers au sein du pool. Sa création est peu coûteuse, créez-en donc un par tâche. Les propriétés sont héritées depuis le pool, ce qui signifie que vous définissez une valeur par défaut une seule fois et que vous la remplacez là où c'est nécessaire.

sudo zfs create tank/data
sudo zfs create tank/pg
sudo zfs set compression=lz4 tank
sudo zfs set atime=off tank
sudo zfs set quota=20G tank/data
sudo zfs set recordsize=16K tank/pg
zfs get -r compression,compressratio,quota tank

La compression est la propriété que les utilisateurs oublient par prudence, ce qui est une erreur. lz4 consomme un peu de CPU et réduit le nombre d'octets devant atteindre le disque ; sur des données compressibles, cela accélère donc généralement les lectures et les écritures. zstd compresse davantage au prix d'une charge CPU plus élevée, ce qui convient aux journaux et aux archives rarement consultés. Vérifiez le résultat réel avec zfs get compressratio tank, en gardant à l'esprit que le ratio ne prend en compte que les données écrites après l'activation de la propriété.

recordsize correspond à la taille maximale des blocs écrits par un dataset, fixée par défaut à 128K. Une base de données écrivant des pages de 8 KiB dans des enregistrements de 128 KiB transforme une petite écriture en une lecture de l'enregistrement complet, une modification, puis une réécriture. Définissez recordsize=16K sur le dataset de la base de données avant d'importer les données, car la propriété ne s'applique qu'aux nouveaux blocs écrits.

quota est le moyen d'empêcher un dataset de saturer le pool. Un pool ZFS proche de 100 % d'utilisation devient lent et difficile à nettoyer ; prévoyez donc volontairement une marge de manœuvre.

Les snapshots ne coûtent rien tant que les données ne changent pas

ZFS n'écrase jamais un bloc actif. Il écrit un nouveau bloc et met à jour les pointeurs, ce qui définit le principe du copy-on-write. Un snapshot est une simple note indiquant « conserver les blocs pointés par ce dataset à cet instant précis », sa création est donc instantanée et gratuite.

sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/data

La colonne USED d'un snapshot représente l'espace occupé uniquement par ce snapshot. Elle commence proche de zéro et augmente à mesure que vous modifiez ou supprimez des données, car les anciens blocs ne peuvent plus être libérés.

La récupération d'un fichier ne nécessite aucune procédure de restauration.

ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txt

Le répertoire .zfs est masqué, même pour ls -a, tant que vous n'exécutez pas sudo zfs set snapdir=visible tank/data. Prenez vos snapshots avant d'en avoir besoin, car sans eux, une commande rm -rf malencontreuse vous renvoie vers la procédure de récupération ext4, qui commence par le démontage du disque et se complique rapidement.

Le rollback supprime tout ce qui a été écrit depuis le snapshot.

sudo zfs rollback tank/data@2026-08-11

Il refuse l'opération si des snapshots plus récents existent, et -r détruit ces snapshots plus récents pour poursuivre. Vérifiez deux fois le nom du dataset avant de valider.

Un snapshot n'est pas une sauvegarde. Il réside dans le même pool, sur le même volume, sur le même serveur. Une défaillance de volume ou un serveur zpool destroy emporte les snapshots avec les données. Les snapshots vous protègent contre vos propres rm et contre une mise à jour défectueuse, ce qui couvre de nombreux incidents réels, mais ils ne protègent contre rien de ce qui affecte le pool lui-même. L'argument complet est détaillé ici : pourquoi un snapshot de VPS n'est pas une sauvegarde.

Envoyer et recevoir : la réplication en une commande

zfs send transforme un snapshot en un flux d'octets sur la sortie standard, et zfs receive convertit ce flux en un dataset. La première copie est un envoi complet.

sudo zfs snapshot tank/data@daily-2026-08-11
sudo zfs send tank/data@daily-2026-08-11 | ssh backup.example.com "sudo zfs recv -F backup/data"

Ensuite, envoyez uniquement les modifications entre deux snapshots.

sudo zfs snapshot tank/data@daily-2026-08-12
sudo zfs send -i tank/data@daily-2026-08-11 tank/data@daily-2026-08-12 | ssh backup.example.com "sudo zfs recv backup/data"

Le côté récepteur doit toujours conserver le snapshot source de l'envoi. Si ce n'est pas le cas, la réception s'arrête avec cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source, car ZFS n'a pas de base sur laquelle appliquer la différence. Envoyez depuis un snapshot présent des deux côtés, ou recommencez avec un envoi complet.

Accordez les droits sur la cible au lieu d'utiliser le root distant : sudo zfs allow -u backupuser create,mount,receive backup/data.

Il s'agit d'une véritable sauvegarde hors site, sous une condition. La destination doit être un pool ZFS, car le stockage objet ne peut pas recevoir un flux. Lorsque votre cible est un stockage compatible S3 ou un hôte Linux standard, utilisez un outil adapté, et sauvegardes restic depuis un VPS couvre cette approche.

Pourquoi ZFS utilise-t-il autant de RAM ? L'ARC

L'ARC (Adaptive Replacement Cache) est le cache de lecture de ZFS. Il réside dans la mémoire du noyau plutôt que dans le cache de pages Linux standard, donc free -h ne le comptabilise pas dans buff/cache. Il apparaît comme de la mémoire utilisée. Un serveur ZFS qui semble presque saturé est généralement un serveur avec un cache chaud, ce qui explique la plupart des rapports indiquant que "ZFS a consommé toute ma RAM".

La limite par défaut est volontairement généreuse. OpenZFS 2.3 définit la taille maximale de l'ARC comme étant la valeur la plus élevée entre la RAM moins 1 GiB et 5/8 de la RAM. OpenZFS 2.2 et les versions antérieures utilisaient la moitié de la RAM sous Linux, alors que FreeBSD appliquait déjà la règle plus récente. Exécutez zfs version pour voir laquelle s'applique à votre système.

ChartDefault maximum ARC size by instance RAM, from the OpenZFS default rule (GiB)
The data behind this chart
[
  {
    "label": "2 GB VPS",
    "openzfs_2_2_linux_gib": 1,
    "openzfs_2_3_gib": 1.25
  },
  {
    "label": "4 GB VPS",
    "openzfs_2_2_linux_gib": 2,
    "openzfs_2_3_gib": 3
  },
  {
    "label": "8 GB VPS",
    "openzfs_2_2_linux_gib": 4,
    "openzfs_2_3_gib": 7
  },
  {
    "label": "16 GB VPS",
    "openzfs_2_2_linux_gib": 8,
    "openzfs_2_3_gib": 15
  }
]

Ces chiffres correspondent à la règle par défaut documentée pour des tailles d'instances courantes, et non à des mesures effectuées sur un serveur en cours d'exécution. Sur une instance de 4 Go, la règle 2.3 autorise un ARC de 3 GiB. La même machine en version 2.2 s'arrête à 2 GiB. Une instance de 2 Go sous la règle 2.3 autorise toujours 1.25 GiB. Votre application récupère ce qu'il reste.

Lisez les chiffres réels sur votre propre serveur au lieu de vous fier au tableau :

grep -E '^(size|c_max) ' /proc/spl/kstat/zfs/arcstats
arc_summary | head -n 20

La troisième colonne indique les octets. c_max est le plafond actuellement en vigueur, et size est la taille actuelle de l'ARC.

L'ARC restitue bien la mémoire. Le noyau signale une pression mémoire et l'ARC se réduit. Le problème est une question de timing, car la réduction est déclenchée par cette pression. Ainsi, un processus demandant plusieurs centaines de MiB d'un coup peut être stoppé par l'OOM (Out Of Memory) killer pendant que l'ARC est encore en train de libérer de l'espace. Sur une machine de 2 Go exécutant une base de données et un serveur web, ce n'est pas un événement rare. Le manuel d'OpenZFS indique la même chose concernant les modifications manuelles : réduire la limite "ne provoquera pas la réduction de l'ARC sans pression mémoire pour induire cette réduction".

Comment limiter l'ARC sur un petit VPS

Déterminez d'abord la mémoire nécessaire à votre charge de travail. Additionnez les besoins de la base de données et de l'application, gardez une marge pour le système d'exploitation, et allouez le reste à l'ARC. Sur une instance de 4 Go exécutant Postgres et une application web, une valeur comprise entre 512 MiB et 1 GiB pour l'ARC constitue un point de départ raisonnable.

Appliquez la limite en temps réel, en octets. Voici l'exemple pour 1 GiB.

echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_max

Rendez ce réglage persistant après un redémarrage.

echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -u

L'étape de l'initramfs est importante car le module peut se charger depuis l'initramfs avant que le système de fichiers racine ne soit monté, ce qui empêcherait la lecture du fichier que vous venez de créer. Après le redémarrage, vérifiez la valeur avec la ligne c_max issue de arcstats.

Le manuel souligne deux points importants. Vous ne pouvez pas remettre la valeur à 0 pendant que le système tourne ; pour annuler ce réglage, il faut modifier le fichier et redémarrer. De plus, réduire cette valeur ne diminue pas instantanément un ARC déjà volumineux.

Sur FreeBSD, cette limite est un sysctl sous vfs.zfs.arc. Exécutez sysctl vfs.zfs.arc pour afficher les valeurs actuelles et le nom exact utilisé par votre version, puis écrivez le maximum dans /boot/loader.conf.

Deux règles de mémoire supplémentaires pour un petit serveur. Désactivez la déduplication, car la table de déduplication réside en mémoire et la règle empirique courante est de 1 à 3 Go de RAM par To de données uniques. Ne placez pas non plus le swap sur un zvol (un périphérique bloc créé à partir du pool), car effectuer un swap via le système de fichiers qui tente justement de libérer de la mémoire peut bloquer la machine. Conservez le swap sur une partition standard ou un fichier de swap situé en dehors du pool.

Quand ext4 ou XFS avec restic est la meilleure solution

ZFS se justifie sur un serveur disposant de mémoire vive excédentaire et d'un second volume. En dehors de ce cas, un système de fichiers classique couplé à un véritable outil de sauvegarde est préférable. Choisissez ext4 ou XFS lorsque :

  • L'instance dispose de 2 Go ou 4 Go de RAM et que la charge de travail nécessite la totalité de ces ressources.
  • Il n'y a qu'un seul disque virtuel sans copie secondaire, ce qui signifie que ZFS permet la détection des erreurs sans pouvoir les réparer.
  • Votre cible de sauvegarde est un stockage objet ou un hôte Linux standard, car rien sur ces cibles ne peut recevoir un flux zfs send.
  • Vous utilisez Debian avec DKMS et ne pouvez pas vous permettre une mise à jour du noyau qui laisserait le module non compilé.
  • Vous avez besoin de ZFS sur le système de fichiers racine et les images fournies par votre hébergeur ne proposent que ext4.

Conservez ZFS si vous disposez d'un volume de données séparé, de RAM disponible (8 Go et plus est confortable) et d'un plan qui utilise réellement les snapshots et zfs send plutôt que de simplement les activer. Pour tout le reste, ext4 avec restic, qui écrit des sauvegardes chiffrées et dédupliquées vers un stockage que le serveur ne contrôle pas, couvre la plupart des besoins sans consommer de mémoire supplémentaire.

Modes de défaillance et messages associés

Le pool disparaît après un redémarrage. zpool status affiche no pools available. Le service d'importation lit /etc/zfs/zpool.cache ; un pool absent de ce fichier n'est donc jamais importé au démarrage. sudo zpool import liste les pools importables, sudo zpool import tank le restaure, et sudo zpool set cachefile=/etc/zfs/zpool.cache tank rend l'opération persistante. Un pool qui n'a pas été exporté proprement depuis un autre système renvoie cannot import 'tank': pool may be in use from other system, et sudo zpool import -f tank force l'importation une fois que vous avez vérifié qu'aucun autre hôte ne l'utilise.

modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... sur Debian après une mise à jour du noyau. DKMS n'a pas compilé pour le nouveau noyau, généralement parce que les headers correspondants ne sont pas installés. dkms status indique ce qui est compilé pour chaque noyau. sudo apt install -y linux-headers-$(uname -r) puis sudo dkms autoinstall reconstruisent le module, et sudo zpool import tank restaure le pool.

Le pool est plein mais vous avez supprimé les fichiers. Les données supprimées restent sur le disque tant qu'un snapshot y fait référence ; c'est pourquoi du et df affichent des valeurs divergentes. zfs list -o space -r tank détaille l'utilisation entre USEDDS et USEDSNAP ; une valeur élevée dans USEDSNAP est la cause. Supprimez les anciens snapshots avec sudo zfs destroy tank/data@2026-06-01 pour récupérer l'espace.

Les erreurs CKSUM augmentent dans zpool status. Un composant sous ZFS a renvoyé des données corrompues. Sur un miroir, ce compteur est un avertissement et le bloc a été réparé. Sur un pool à disque unique, le fichier est perdu, zpool status -v l'identifie, et vous devez restaurer ce fichier depuis une sauvegarde externe à ce pool.

Le serveur est lent et utilise le swap. Limitez l'ARC comme indiqué précédemment, puis exécutez arc_summary et vérifiez le taux de succès (hit ratio). Un ARC trop petit pour contenir le jeu de travail signifie que chaque lecture accède au disque ; dans ce cas, un système de fichiers classique utilisant le cache de pages serait plus performant.

FAQ

De combien de RAM ZFS a-t-il besoin sur un VPS ?

ZFS fonctionne sur une instance de 2 Go. La vraie question est de savoir ce qu'il reste pour votre application. Sans réglage spécifique, OpenZFS 2.3 laisse l'ARC croître jusqu'à la plus grande valeur entre la RAM moins 1 GiB et 5/8 de la RAM. Ainsi, une machine de 4 Go peut allouer 3 GiB au cache. Définissez zfs_arc_max sur une valeur que votre charge de travail peut supporter, puis confirmez-la en lisant la ligne c_max dans /proc/spl/kstat/zfs/arcstats.

Un snapshot ZFS est-il une sauvegarde ?

Non. Un snapshot réside dans le même pool que les données. Il survit à une mauvaise rm et à une mise à jour ratée, mais il disparaît avec le pool ou l'instance. Transformez-le en sauvegarde en l'envoyant sur une autre machine avec zfs send, ou en utilisant un outil de sauvegarde qui écrit sur un stockage que ce serveur ne contrôle pas.

ZFS fonctionne-t-il de la même manière sur FreeBSD et Linux ?

Il s'agit de la même base de code depuis OpenZFS 2.0 en décembre 2020, les mêmes commandes, le même format sur disque, et les pools sont portables entre les deux systèmes. La différence réside dans le packaging. FreeBSD intègre ZFS dans son système de base. Sur Linux, chaque distribution décide : Ubuntu compile le module dans ses paquets noyau, tandis que Debian le compile sur votre machine avec DKMS. Une mise à jour du noyau peut donc vous laisser sans module tant que la reconstruction n'a pas réussi.

ZFS peut-il réparer une corruption sur un VPS avec un seul disque ?

Il détecte la corruption et identifie le fichier, mais il ne peut pas le réparer, car la réparation nécessite une seconde copie du bloc. zfs set copies=2 sur un dataset vous fournit cette seconde copie pour le double de l'espace, ce qui gère un bloc défectueux mais pas un volume perdu. Un miroir sur deux volumes est la solution qui permet réellement de réparer.

La compression ralentit-elle le serveur ?

lz4 rend généralement le serveur plus rapide. Les blocs compressés signifient moins d'octets écrits et moins d'octets lus, et le coût CPU par bloc est négligeable par rapport à l'espace disque économisé. Définissez compression=lz4 à la racine du pool pour que chaque dataset en hérite, puis vérifiez zfs get compressratio tank une fois que des données réelles ont été écrites.