ZFS sur VPS : quel coût en RAM avec FreeBSD et Linux ?
ZFS offre checksums, snapshots, réplication et compression, mais l’ARC consomme votre RAM. Évaluez ce compromis sur un VPS de 2 ou 4 Go.
Ce que ZFS vous apporte et ce qu’il exige
ZFS sur FreeBSD et Linux repose désormais sur une même base de code, OpenZFS. Les fonctionnalités sont donc identiques sur les deux systèmes. Un serveur qui utilise ZFS bénéficie de données protégées par checksum, de snapshots qui ne consomment pas d’espace tant que les données ne changent pas, de la réplication avec zfs send et de la compression, activable avec une seule propriété. En contrepartie, ZFS consomme de la mémoire : l’ARC (adaptive replacement cache) utilise par défaut une part importante de la RAM. Sur un VPS (virtual private server) de 2 GB ou 4 GB, cette mémoire est précisément celle dont votre application a besoin.
Ce guide évalue ZFS sur un VPS loué avec un ou deux disques virtuels, et non sur une baie de stockage équipée de quarante emplacements pour disques. Les fonctionnalités qui restent utiles dans ce contexte méritent votre attention. Il est également important de connaître les limites qui apparaissent avant de créer un pool.
OpenZFS sur FreeBSD et Linux : une base de code, deux modes de packaging
FreeBSD intègre ZFS au système de base depuis FreeBSD 7.0, sorti en 2008, d’abord comme fonctionnalité expérimentale. Depuis OpenZFS 2.0, sorti en décembre 2020, FreeBSD et Linux compilent le code depuis le même arbre source. zfs et zpool se comportent donc de la même manière sur les deux systèmes, et un pool créé sur l’un peut être importé sur l’autre.
Si ZFS est un package sous Linux et une composante du système de base sous FreeBSD, c’est pour des raisons de licence. OpenZFS est distribué sous la CDDL (common development and distribution license). Le noyau Linux est distribué sous la GPL (general public license) version 2. Le projet du noyau considère ces deux licences comme incompatibles. Le code ZFS n’est donc pas intégré au noyau Linux mainline, et chaque distribution détermine comment le fournir. FreeBSD ne présente pas ce conflit, donc ZFS y est directement disponible. C’est toute la différence pratique : un mode de packaging différent, sans conséquence nécessitant de prendre parti.
SSD Nodes ne propose pas d’images FreeBSD. Sur un serveur loué auprès de ce fournisseur, 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 et sans mise à niveau du noyau à maintenir.
Installer ZFS et créer un pool
Sur Ubuntu, le module est fourni dans les paquets du noyau. Vous devez donc seulement installer les commandes.
sudo apt update
sudo apt install -y zfsutils-linux
zfs versionzfs version affiche deux lignes : la version de l’espace utilisateur et celle du module du noyau. Une seule ligne signifie que le module n’a pas été chargé. Le paquet se trouve dans le composant universe, activé par défaut par 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-linuxL’installation compile le module et affiche Building initial module for 6.12.0-..., ce qui prend quelques minutes. Retenez ce que cela implique : chaque mise à niveau du noyau le recompilera, et un échec de compilation laissera votre pool non importé jusqu’à la résolution du problème.
Sur FreeBSD, rien n’est installé. Activez le service et démarrez-le.
sysrc zfs_enable=YES
service zfs startCréez maintenant le pool. Commencez par consulter les chemins stables des périphériques, car /dev/vdb est attribué selon l’ordre de détection et peut changer lorsque vous connectez un autre volume.
ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tankzpool status doit afficher state: ONLINE, avec votre périphérique sous tank. ashift=12 fixe la taille minimale des blocs du pool à 4 KiB. Cette valeur convient aux SSD actuels et ne peut plus être modifiée après la création.
La plupart des images louées démarrent depuis une partition racine ext4. Dans ce cas, ZFS sert donc pour un pool de données sur un second volume, et non pour le système de fichiers racine. Vérifiez que le périphérique correspond bien à celui prévu avant de l’utiliser, car confirmer le disque NVMe qui vous a été vendu prend une minute, tandis qu’une reconstruction prend un après-midi.
Les sommes de contrôle ne permettent une réparation que si le pool dispose d’une redondance
Chaque bloc écrit par ZFS contient une somme de contrôle, qui est vérifiée à chaque lecture. La détection fonctionne toujours. La réparation nécessite une seconde copie.
Sur un pool à un seul disque, ZFS vous indique le problème, puis 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.tarLe fichier endommagé est indiqué. ext4 aurait renvoyé ces octets sans commentaire, ce qui est déjà utile. ZFS ne peut toutefois pas le réparer, car le pool ne contient aucune seconde copie permettant de le faire.
Avec un mirror, la même lecture est effectuée depuis le côté intact, le bloc endommagé est réécrit et l’événement apparaît dans la colonne CKSUM de zpool status. C’est l’auto-réparation, qui nécessite deux périphériques.
sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2Sur un VPS, le stockage de l’hôte est généralement déjà redondant, souvent avec un RAID 10 sous l’hyperviseur. Cela vous protège contre la panne d’un disque. En revanche, cela ne vous indique pas qu’un bloc a été renvoyé avec des données incorrectes, car la baie ne peut pas 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 disposez d’un seul disque virtuel et souhaitez bénéficier d’une certaine 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 défectueux et 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 tankUn pool sain se termine par une ligne comme scan: scrub repaired 0B in 00:04:11 with 0 errors. Planifiez cette opération régulièrement ; une fois par mois convient pour un petit pool.
systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timerLes datasets sont l’unité de gestion des règles
Un dataset est un système de fichiers situé dans le pool. Sa création coûte peu, alors créez-en un par tâche. Les propriétés sont héritées du pool. Vous définissez donc une valeur par défaut une seule fois, puis vous la remplacez là où c’est nécessaire. Sous FreeBSD, les jails sont généralement exécutées de cette manière : un dataset par jail permet de créer un snapshot et de restaurer chaque jail indépendamment. C’est l’un des éléments de ce qui distingue une jail d’un conteneur Docker.
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 tankLa compression est la propriété que l’on omet par prudence. C’est une mauvaise approche. lz4 consomme peu de CPU et réduit le nombre d’octets à écrire sur le disque. Pour les données compressibles, elle accélère donc généralement les lectures et les écritures. zstd compresse davantage au prix d’une consommation CPU supérieure. Elle convient aux logs et aux archives que vous relisez rarement. Vérifiez le résultat réel avec zfs get compressratio tank. Gardez à l’esprit que le ratio ne concerne que les données écrites après la définition de la propriété.
recordsize correspond à la taille maximale des blocs écrits par un dataset. La valeur par défaut est 128K. Une base de données qui écrit des pages de 8 KiB dans des enregistrements de 128 KiB transforme chaque petite écriture en lecture de l’enregistrement complet, suivie d’une modification et d’une réécriture. Définissez recordsize=16K sur le dataset de la base de données avant d’y charger les données, car cette propriété ne s’applique qu’aux nouveaux blocs écrits.
quota permet d’empêcher un dataset de remplir le pool. Un pool ZFS presque plein à 100 % devient lent et difficile à nettoyer. Laissez donc volontairement de l’espace libre.
Les snapshots ne consomment rien tant que les données ne changent pas
ZFS ne réécrit jamais un bloc utilisé. Il écrit un nouveau bloc et met à jour les pointeurs : c’est le principe du copy-on-write. Un snapshot indique « conserver les blocs vers lesquels ce dataset pointe actuellement ». Sa création est donc instantanée et ne consomme pas d’espace.
sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/dataLa colonne USED d’un snapshot indique l’espace occupé uniquement par ce snapshot. Elle est presque nulle au départ, puis augmente lorsque vous modifiez ou supprimez des données, car les anciens blocs ne peuvent plus être libérés.
Récupérer un fichier ne nécessite aucune étape de restauration.
ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txtLe répertoire .zfs est masqué, y compris pour ls -a, jusqu’à l’exécution de sudo zfs set snapdir=visible tank/data. Créez le snapshot avant d’en avoir besoin : sans snapshot, un simple rm -rf vous envoie vers la procédure de récupération ext4, qui commence par démonter le disque et devient plus complexe ensuite.
Un rollback supprime tout ce qui a été écrit depuis le snapshot.
sudo zfs rollback tank/data@2026-08-11L’opération est refusée lorsque des snapshots plus récents existent. -r supprime ces snapshots plus récents pour poursuivre. Vérifiez deux fois le nom du dataset avant d’appuyer sur Entrée.
Un snapshot n’est pas une sauvegarde. Il se trouve dans le même pool, sur le même volume et sur le même serveur. Un volume défaillant ou un zpool destroy emporte les snapshots avec les données. Les snapshots vous protègent contre vos propres rm et contre une mise à niveau défectueuse. Cela couvre de nombreux incidents réels, mais ils ne vous protègent pas contre les problèmes qui touchent le pool lui-même. Le cas complet est présenté 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 flux d’octets sur la sortie standard, et zfs receive transforme ce flux en 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 changements 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 système de réception doit toujours conserver le snapshot depuis lequel vous envoyez les données. Sinon, la réception s’arrête avec cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source, car ZFS ne dispose d’aucune base pour appliquer la différence. Envoyez depuis un snapshot conservé des deux côtés, ou recommencez avec un envoi complet.
Accordez les droits sur la cible au lieu d’utiliser root à distance : sudo zfs allow -u backupuser create,mount,receive backup/data.
Il s’agit d’une véritable sauvegarde hors site, sous une condition. L’extrémité distante doit être un pool ZFS, car un stockage objet ne peut pas recevoir de flux. Si votre cible est un stockage compatible S3 ou un hôte Linux classique, utilisez un outil qui sait communiquer avec cette cible. Les sauvegardes restic depuis un VPS couvrent ce cas.
Pourquoi ZFS utilise-t-il autant de RAM ? L’ARC
L’ARC (adaptive replacement cache) est le cache de lecture de ZFS. Il se trouve dans la mémoire du kernel, et non dans le page cache normal de Linux. Par conséquent, free -h ne l’affiche pas dans buff/cache. Il apparaît comme de la mémoire utilisée. Un serveur ZFS qui semble presque saturé dispose généralement d’un cache bien alimenté. Cela explique la plupart des signalements indiquant que « ZFS a pris toute ma RAM ».
La limite par défaut est volontairement élevée. OpenZFS 2.3 définit la taille maximale de l’ARC comme la plus grande valeur 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, tandis que FreeBSD appliquait déjà la nouvelle règle. Exécutez zfs version pour savoir quelle règle s’applique à votre système.
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 valeurs correspondent à la règle par défaut documentée, appliquée à des tailles d’instance courantes. Il ne s’agit pas de mesures relevées sur un serveur en fonctionnement. Sur une instance de 4 GB, la règle de la version 2.3 autorise un ARC de 3 GiB. La même machine sous la version 2.2 est limitée à 2 GiB. Une instance de 2 GB utilisant la règle de la version 2.3 autorise encore 1.25 GiB. Votre application dispose du reste.
Lisez les valeurs réelles 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 20La troisième colonne indique le nombre d’octets. c_max correspond à la limite actuellement appliquée, et size à la taille actuellement occupée par l’ARC.
L’ARC restitue bien de la mémoire. Le kernel signale la pression mémoire, puis l’ARC réduit sa taille. Le problème vient du délai de réaction : la réduction est déclenchée par cette pression. Un processus qui demande plusieurs centaines de MiB en une seule fois peut donc être confronté à l’OOM (out of memory) killer alors que l’ARC est encore en train de libérer de la mémoire. Sur un serveur de 2 GB qui exécute une base de données et un serveur web, ce cas n’est pas rare. Le manuel d’OpenZFS indique la même chose concernant les modifications manuelles : la réduction de la limite « n’entraîne pas la réduction de l’ARC en l’absence de pression mémoire provoquant cette réduction ».
Limiter l’ARC sur un petit VPS
Commencez par déterminer la mémoire nécessaire à la 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, puis attribuez le reste à l’ARC. Sur une instance de 4 GB exécutant Postgres et une application web, une ARC de 512 MiB à 1 GiB constitue un bon point de départ.
Appliquez la valeur immédiatement, en octets. Ici, il s’agit de 1 GiB.
echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_maxFaites en sorte que la valeur soit conservée après un redémarrage.
echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -uL’étape concernant l’initramfs est importante, car le module peut être chargé depuis l’initramfs avant le montage du système de fichiers racine. Il ne lirait alors jamais le fichier que vous venez d’écrire. Après le redémarrage, vérifiez la valeur avec la ligne c_max d’arcstats.
Deux réserves figurent dans le manuel lui-même. Vous ne pouvez pas ramener la valeur à 0 pendant que le système fonctionne. Pour annuler ce réglage, vous devez donc modifier le fichier, puis redémarrer. De plus, réduire cette valeur ne diminue pas immédiatement la taille d’une ARC déjà importante.
Sous FreeBSD, la même limite est un sysctl situé 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 la valeur maximale dans /boot/loader.conf.
Deux autres règles concernent la mémoire d’un petit serveur. Laissez la déduplication désactivée, car la table de déduplication réside en mémoire et la règle empirique couramment publiée prévoit 1 à 3 GB de RAM par TB de données uniques. Ne placez pas non plus le swap sur un zvol (un périphérique bloc créé à partir du pool), car l’utilisation du swap via le système de fichiers qui tente de libérer de la mémoire peut bloquer la machine. Conservez le swap sur une partition classique ou dans un fichier de swap situé en dehors du pool.
Quand ext4 ou XFS avec restic est le meilleur choix
ZFS est pertinent sur un serveur disposant de mémoire disponible et d’un second volume. Dans les autres cas, un système de fichiers classique associé à un véritable outil de sauvegarde est préférable. Choisissez ext4 ou XFS lorsque :
- L’instance dispose de 2 GB ou 4 GB de RAM et que la charge doit en utiliser la totalité.
- Il n’y a qu’un seul disque virtuel et aucune seconde copie ; ZFS permet donc de détecter les erreurs sans pouvoir les corriger.
- La cible de sauvegarde est un object storage ou un hôte Linux classique, qui ne peut donc pas recevoir un flux
zfs send. - Vous utilisez Debian avec DKMS et ne pouvez pas vous permettre une mise à niveau du kernel qui laisserait le module non compilé.
- Vous avez besoin de ZFS sur le root filesystem et les images du fournisseur proposent uniquement ext4.
Conservez ZFS si vous disposez d’un volume de données séparé, de suffisamment de RAM (8 GB et plus offrent un confort correct) et d’un plan qui utilise réellement les snapshots et zfs send, au lieu de simplement les activer. Dans les autres cas, ext4 avec restic, qui écrit des sauvegardes chiffrées et dédupliquées sur un stockage que le serveur ne contrôle pas, couvre l’essentiel du besoin sans mobiliser de mémoire.
Modes de défaillance et messages affichés
Le pool a disparu après un redémarrage. zpool status affiche no pools available. Le service d’import 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 réimporte et sudo zpool set cachefile=/etc/zfs/zpool.cache tank rend ce réglage persistant. Un pool qui n’a pas été exporté proprement depuis un autre système affiche cannot import 'tank': pool may be in use from other system. sudo zpool import -f tank permet de forcer l’import 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 à niveau du noyau. DKMS n’a pas compilé le module pour le nouveau noyau, généralement parce que les en-têtes correspondants ne sont pas installés. dkms status indique quel module a été compilé pour chaque noyau. sudo apt install -y linux-headers-$(uname -r), puis sudo dkms autoinstall le recompile, et sudo zpool import tank réimporte 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 les référence encore. du et df affichent donc des valeurs différentes. zfs list -o space -r tank sépare l’utilisation entre USEDDS et USEDSNAP. Une valeur USEDSNAP élevée explique le problème. Détruisez les anciens snapshots avec sudo zfs destroy tank/data@2026-06-01 pour récupérer l’espace.
Le compteur CKSUM augmente dans zpool status. Un composant situé sous ZFS a renvoyé des données incorrectes. Sur un mirror, le compteur signale un problème et le bloc a été réparé. Dans un pool composé d’un seul disque, le fichier est perdu. zpool status -v indique son nom. Restaurez uniquement ce fichier depuis une sauvegarde qui ne se trouve pas dans ce pool.
Le serveur est lent et utilise le swap. Limitez l’ARC comme indiqué plus haut, puis exécutez arc_summary et consultez le taux de réussite. Si l’ARC est trop petite pour contenir le jeu de travail, chaque lecture accède au disque. Dans ce cas, un système de fichiers classique utilisant le page cache serait plus performant.
FAQ
De combien de RAM ZFS a-t-il besoin sur un VPS ?
ZFS fonctionne sur une instance de 2 GB. La vraie question est de savoir ce qu’il reste pour votre application. Sans réglage, OpenZFS 2.3 permet à l’ARC d’atteindre la plus grande valeur entre la RAM moins 1 GiB et 5/8 de la RAM. Une machine de 4 GB peut donc réserver 3 GiB au cache. Définissez zfs_arc_max avec une valeur que votre charge peut libérer, puis vérifiez-la en lisant la ligne c_max dans /proc/spl/kstat/zfs/arcstats.
Un snapshot ZFS est-il une sauvegarde ?
Non. Un snapshot se trouve dans le même pool que les données. Il survit à un rm défectueux et à une mise à niveau qui échoue, mais il est perdu avec le pool ou l’instance. Transformez-le en sauvegarde en l’envoyant vers une autre machine avec zfs send, ou utilisez 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 repose sur la même base de code depuis OpenZFS 2.0, en décembre 2020. Les commandes et le format sur disque sont identiques, et les pools peuvent être déplacés de l’un à l’autre. La différence concerne le packaging. FreeBSD fournit ZFS dans le système de base. Sous Linux, chaque distribution choisit son mode de fonctionnement : Ubuntu intègre le module à ses paquets de noyau, tandis que Debian le compile sur votre machine avec DKMS. Une mise à niveau du noyau peut donc vous laisser sans module jusqu’à la fin de la compilation.
ZFS peut-il réparer une corruption sur un VPS équipé d’un seul disque ?
Il détecte la corruption et indique le fichier concerné, mais il ne peut pas la réparer, car cette opération nécessite une deuxième copie du bloc. zfs set copies=2 sur un dataset fournit cette deuxième copie au prix d’un doublement de l’espace utilisé. Cela permet de gérer un bloc défectueux, mais pas la perte d’un volume. Un mirror réparti sur deux volumes est la solution qui permet réellement de réparer les données.
La compression ralentit-elle le serveur ?
lz4 accélère généralement le serveur. Les blocs compressés nécessitent moins d’octets écrits et lus, et le coût CPU par bloc reste faible par rapport au volume de données que la compression évite d’écrire. Définissez compression=lz4 à la racine du pool afin que chaque dataset en hérite, puis vérifiez zfs get compressratio tank une fois que les données réelles ont été écrites.