SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-13

ZFS su FreeBSD e Linux: quanta RAM richiede

Checksum, snapshot, replica con send/receive e compressione hanno un costo: scopri come valutare l'uso della ARC su un VPS da 2 o 4 GB di RAM.

Cosa offre ZFS e quali sono i requisiti

ZFS su FreeBSD e Linux utilizza ora un'unica base di codice, OpenZFS, quindi le funzionalità sono le stesse su entrambi i sistemi. Un server che usa ZFS dispone di dati con checksum, snapshot che non consumano spazio finché i dati non cambiano, replica con zfs send e compressione attivabile modificando una sola proprietà. Il requisito principale è la memoria: per impostazione predefinita, ARC (adaptive replacement cache) utilizza una quota significativa della RAM. Su un VPS (virtual private server) da 2 GB o 4 GB, quella memoria è esattamente quella richiesta dall'applicazione.

Questa guida valuta ZFS su un VPS a noleggio con uno o due dischi virtuali, non su un sistema di storage con quaranta alloggiamenti per unità. Le funzionalità che restano utili in questo contesto sono quelle a cui vale la pena dedicare attenzione. È importante conoscere prima di creare un pool anche gli aspetti che invece non si adattano a questo scenario.

OpenZFS su FreeBSD e Linux: una base di codice, due modalità di distribuzione

FreeBSD include ZFS nel sistema di base da FreeBSD 7.0, rilasciato nel 2008, inizialmente come funzionalità sperimentale. Da OpenZFS 2.0, rilasciato a dicembre 2020, FreeBSD e Linux vengono compilati dallo stesso albero dei sorgenti. Di conseguenza, zfs e zpool si comportano allo stesso modo su entrambe le piattaforme e un pool creato su una piattaforma può essere importato sull'altra.

Il motivo per cui ZFS è un pacchetto su Linux e fa parte del sistema di base su FreeBSD è la licenza. OpenZFS è distribuito con la CDDL (Common Development and Distribution License). Il kernel Linux è distribuito con la GPL (General Public License) versione 2. Il progetto del kernel considera le due licenze incompatibili. Per questo il codice ZFS non viene integrato nel ramo principale di Linux e ogni distribuzione decide come distribuirlo. FreeBSD non presenta questo conflitto, quindi ZFS è già incluso. In pratica, la differenza riguarda soltanto la modalità di distribuzione e non richiede di prendere posizione.

SSD Nodes non offre immagini FreeBSD. Su un server noleggiato tramite questo provider si applica quindi la parte della guida relativa a Linux. Se esegui FreeBSD altrove, un server FreeBSD include ZFS senza dover compilare moduli e senza dover gestire aggiornamenti del kernel.

Installare ZFS e creare un pool

Su Ubuntu il modulo è incluso nei pacchetti del kernel, quindi è sufficiente installare i comandi.

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

zfs version stampa due righe: la versione dello spazio utente e la versione del modulo del kernel. Se viene stampata una sola riga, il modulo non è stato caricato. Il pacchetto si trova nel componente universe, che le immagini Ubuntu Server abilitano per impostazione predefinita; se apt non riesce a trovarlo, eseguire prima sudo add-apt-repository universe.

Su Debian i pacchetti si trovano nel componente contrib e il modulo viene compilato sul computer tramite DKMS (supporto dinamico dei moduli del kernel). Aggiungere contrib alla riga Components: in /etc/apt/sources.list.d/debian.sources, eseguire sudo apt update, quindi:

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

L'installazione compila il modulo e stampa Building initial module for 6.12.0-.... L'operazione richiede alcuni minuti. Questo comporta che ogni aggiornamento del kernel ricompili il modulo. Se la compilazione non riesce, il pool non viene importato finché il problema non viene risolto.

Su FreeBSD non è installato nulla. Abilitare il servizio e avviarlo.

sysrc zfs_enable=YES
service zfs start

Ora creare il pool. Controllare prima i percorsi stabili dei dispositivi, perché /dev/vdb viene assegnato in base all'ordine di rilevamento e può cambiare quando si collega un altro 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 dovrebbe stampare state: ONLINE, con il dispositivo elencato sotto tank. ashift=12 imposta a 4 KiB il blocco minimo del pool. Questo valore corrisponde agli SSD attuali e non può essere modificato dopo la creazione.

La maggior parte delle immagini noleggiate avvia il sistema da una partizione root ext4. In questo caso ZFS viene usato per un pool di dati su un secondo volume, non per il filesystem root. Verificare che il dispositivo sia quello previsto prima di usarlo, perché confermare il disco NVMe acquistato richiede un minuto, mentre una ricostruzione richiede un pomeriggio.

I checksum correggono gli errori solo quando il pool dispone di ridondanza

Ogni blocco scritto da ZFS contiene un checksum, che viene verificato a ogni lettura. Il rilevamento funziona sempre. La correzione richiede una seconda copia.

In un pool con un solo disco, ZFS segnala il problema e non può fare altro. zpool status -v lo riporta in questo modo:

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

Viene indicato il file danneggiato. ext4 avrebbe restituito quei byte senza segnalare nulla, quindi questo risultato è già utile. ZFS non può comunque correggere il problema, perché nel pool non esiste una seconda copia da cui recuperare i dati.

Con un mirror, la stessa lettura viene servita dalla copia integra, il blocco danneggiato viene riscritto e l'evento compare nella colonna CKSUM di zpool status. Questa è la correzione automatica e richiede due dispositivi.

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

Su un VPS, lo storage dell'host è in genere già ridondante, spesso con RAID 10 sotto l'hypervisor. Questo protegge dal guasto di un'unità. Non segnala però quando un blocco viene restituito con dati errati, perché l'array non può sapere quale copia sia corretta. ZFS lo sa, perché confronta i dati con un checksum che ha calcolato e scritto direttamente.

Se hai un solo disco virtuale e vuoi disporre di una certa capacità di correzione, sudo zfs set copies=2 tank/important memorizza due copie di ogni blocco del dataset sullo stesso disco. Questo raddoppia lo spazio occupato dal dataset, consente di superare un blocco danneggiato, ma non serve a nulla se l'intero volume scompare.

Uno scrub legge tutti i dati del pool e ne verifica l'integrità.

sudo zpool scrub tank
zpool status tank

Un pool integro termina con una riga come scan: scrub repaired 0B in 00:04:11 with 0 errors. Pianifica questa operazione; una volta al mese è sufficiente per un pool di piccole dimensioni.

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

I dataset sono l'unità delle policy

Un dataset è un filesystem all'interno del pool. Crearlo è semplice, quindi conviene crearne uno per ogni attività. Le proprietà vengono ereditate dal pool verso il basso. È quindi possibile impostare un valore predefinito una sola volta e sovrascriverlo dove necessario.

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 compressione è la proprietà che molti omettono per prudenza, ma è un approccio sbagliato. lz4 richiede una quantità ridotta di CPU e diminuisce i byte da scrivere sul disco. Sui dati comprimibili, di solito accelera sia le letture sia le scritture. zstd applica una compressione più efficace al costo di un maggiore utilizzo della CPU. È adatta a log e archivi che vengono consultati raramente. Verifica il risultato effettivo con zfs get compressratio tank e ricorda che il rapporto considera soltanto i dati scritti dopo l'impostazione della proprietà.

recordsize è la dimensione massima del blocco scritto da un dataset, pari a 128K per impostazione predefinita. Un database che scrive pagine da 8 KiB in record da 128 KiB trasforma una piccola scrittura nella lettura dell'intero record, in una modifica e nella successiva riscrittura. Imposta recordsize=16K sul dataset del database prima di caricare i dati, perché la proprietà si applica soltanto ai blocchi scritti successivamente.

quota impedisce a un dataset di riempire l'intero pool. Un pool ZFS quasi pieno al 100% diventa lento e difficile da ripulire, quindi è opportuno lasciare deliberatamente spazio libero.

Gli snapshot non occupano spazio finché i dati non cambiano

ZFS non sovrascrive mai un blocco in uso. Scrive un nuovo blocco e aggiorna i puntatori: questo è il significato di copy-on-write. Uno snapshot indica di conservare i blocchi a cui il dataset punta in quel momento, quindi la sua creazione è immediata e non occupa spazio.

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

La colonna USED di uno snapshot indica lo spazio occupato esclusivamente da quello snapshot. Inizialmente è quasi pari a zero e aumenta quando modifichi o elimini dati, perché i blocchi precedenti non possono più essere rilasciati.

Per recuperare un file non è necessaria alcuna procedura di ripristino.

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

La directory .zfs è nascosta anche a ls -a finché non esegui sudo zfs set snapdir=visible tank/data. Crea lo snapshot prima di averne bisogno: senza uno snapshot, un semplice rm -rf ti porta nel percorso di ripristino ext4, che inizia con lo smontaggio del disco e da lì la situazione peggiora.

Il rollback elimina tutto ciò che è stato scritto dopo lo snapshot.

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

L'operazione viene rifiutata se esistono snapshot più recenti; -r elimina questi snapshot per procedere. Controlla due volte il nome del dataset prima di premere Invio.

Uno snapshot non è un backup. Si trova nello stesso pool, sullo stesso volume e sullo stesso server. Un guasto al volume o un singolo zpool destroy elimina gli snapshot insieme ai dati. Gli snapshot proteggono da un tuo rm e da un aggiornamento non riuscito, coprendo molti incidenti reali, ma non proteggono da ciò che accade al pool stesso. Il quadro completo è disponibile qui: perché uno snapshot VPS non è un backup.

Invio e ricezione: replica con un solo comando

zfs send converte uno snapshot in un flusso di byte sullo standard output, mentre zfs receive riconverte quel flusso in un dataset. La prima copia è un invio completo.

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"

Successivamente, invia soltanto le modifiche tra due snapshot.

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"

Il sistema ricevente deve conservare lo snapshot da cui stai eseguendo l’invio. In caso contrario, la ricezione si interrompe con cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source, perché ZFS non dispone di una base a cui applicare le differenze. Esegui l’invio a partire da uno snapshot conservato su entrambi i lati oppure riparti con un invio completo.

Concedi i diritti sul sistema di destinazione invece di usare root remoto: sudo zfs allow -u backupuser create,mount,receive backup/data.

Si tratta di un backup off-site reale, con una condizione. Il sistema remoto deve utilizzare un pool ZFS, perché l’object storage non può ricevere un flusso. Se la destinazione è uno storage compatibile con S3 o un host Linux standard, usa uno strumento che supporti quel sistema. I backup restic da un VPS illustrano questo percorso.

Perché ZFS usa così tanta RAM? L'ARC

L'ARC (adaptive replacement cache) è la cache di lettura di ZFS. Risiede nella memoria del kernel, non nella normale page cache di Linux, quindi free -h non la riporta nella voce buff/cache. Viene visualizzata come memoria in uso. Un server ZFS che sembra quasi pieno ha in genere una cache già popolata; questo spiega la maggior parte delle segnalazioni secondo cui «ZFS ha consumato tutta la RAM».

Il limite predefinito è volutamente elevato. OpenZFS 2.3 imposta la dimensione massima dell'ARC sul valore maggiore tra RAM meno 1 GiB e 5/8 della RAM. OpenZFS 2.2 e versioni precedenti usavano metà della RAM su Linux, mentre FreeBSD applicava già la regola più recente. Esegui zfs version per verificare quale regola è in vigore sul tuo sistema.

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
  }
]

Questi valori applicano la regola predefinita documentata a dimensioni comuni delle istanze; non sono misurazioni effettuate su un server in esecuzione. Su un'istanza da 4 GB, la regola della versione 2.3 consente un ARC di 3 GiB. Lo stesso server con la versione 2.2 si ferma a 2 GiB. Un'istanza da 2 GB con la regola della versione 2.3 consente comunque 1.25 GiB. Alla tua applicazione resta la memoria residua.

Leggi i valori effettivi direttamente dal tuo server, invece di fare affidamento sulla tabella:

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

La terza colonna contiene i byte. c_max è il limite massimo attualmente in vigore, mentre size indica quanta memoria contiene attualmente l'ARC.

L'ARC restituisce memoria al sistema. Il kernel segnala la pressione sulla memoria e l'ARC si riduce. Il problema riguarda i tempi: la riduzione è attivata da quella pressione, quindi un processo che richiede in un'unica operazione diverse centinaia di MiB può raggiungere l'OOM (out of memory) killer mentre l'ARC sta ancora rilasciando memoria. Su un server da 2 GB che esegue un database e un web server, non è un evento raro. Il manuale di OpenZFS afferma lo stesso anche per le modifiche manuali: la riduzione del limite «non fa diminuire l'ARC in assenza di pressione sulla memoria che ne provochi la riduzione».

Come limitare l'ARC su un VPS di piccole dimensioni

Determina prima la memoria necessaria per il carico di lavoro. Somma la memoria richiesta dal database e dall'applicazione, conserva un margine per il sistema operativo e assegna il resto all'ARC. Su un'istanza da 4 GB che esegue Postgres e un'applicazione web, un valore iniziale compreso tra 512 MiB e 1 GiB per l'ARC è ragionevole.

Applica il valore immediatamente, esprimendolo in byte. In questo esempio è 1 GiB.

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

Fai in modo che il valore venga mantenuto dopo un riavvio.

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

Il passaggio relativo a initramfs è importante perché il modulo può essere caricato da initramfs prima del montaggio del filesystem root. In questo caso non leggerebbe mai il file appena scritto. Dopo il riavvio, verifica il valore con la riga c_max di arcstats.

Dal manuale stesso derivano due precisazioni. Non puoi riportare il valore a 0 mentre il sistema è in esecuzione. Per annullare questa impostazione devi quindi modificare il file e riavviare il sistema. Inoltre, ridurre il valore non ridimensiona immediatamente un ARC di grandi dimensioni.

Su FreeBSD lo stesso limite è un sysctl in vfs.zfs.arc. Esegui sysctl vfs.zfs.arc per visualizzare i valori correnti e il nome esatto usato dalla tua versione, quindi scrivi il valore massimo in /boot/loader.conf.

Per un server di piccole dimensioni valgono altre due regole relative alla memoria. Lascia disattivata la deduplicazione, perché la tabella di deduplicazione risiede in memoria e la regola empirica comunemente pubblicata indica da 1 a 3 GB di RAM per ogni TB di dati univoci. Non usare inoltre uno swap su zvol, cioè un dispositivo a blocchi ricavato dal pool, perché lo swap attraverso il filesystem che sta cercando di liberare memoria può bloccare il sistema. Mantieni lo swap su una partizione normale o su un file di swap esterno al pool.

Quando ext4 o XFS con restic sono la scelta migliore

ZFS è utile su un server con memoria disponibile e un secondo volume. Negli altri casi, un filesystem standard insieme a uno strumento di backup affidabile è una scelta migliore. Scegli ext4 o XFS quando:

  • L'istanza ha 2 GB o 4 GB di RAM e il carico di lavoro deve poterli utilizzare interamente.
  • È presente un solo disco virtuale e non esiste una seconda copia, quindi ZFS rileva i problemi ma non può correggerli.
  • La destinazione del backup è l'object storage o un host Linux standard, quindi non può ricevere uno stream zfs send.
  • Usi Debian con DKMS e non puoi permetterti un aggiornamento del kernel dopo il quale il modulo non venga compilato.
  • Ti serve ZFS sul filesystem root e le immagini del provider offrono soltanto ext4.

Mantieni ZFS quando hai un volume dati separato, RAM disponibile (da 8 GB in su è una configurazione adeguata) e un piano che utilizzi snapshot e zfs send, invece di limitarti ad abilitarli. Negli altri casi, ext4 con restic che scrive backup crittografati e deduplicati su uno storage non controllato dal server copre quasi le stesse esigenze senza consumare memoria aggiuntiva.

Modalità di errore e stringhe visualizzate

Il pool non è più disponibile dopo un riavvio. zpool status stampa no pools available. Il servizio di importazione legge /etc/zfs/zpool.cache, quindi un pool assente da quel file non viene mai importato all'avvio. sudo zpool import elenca ciò che può essere importato, sudo zpool import tank lo ripristina e sudo zpool set cachefile=/etc/zfs/zpool.cache tank rende permanente la configurazione. Un pool che non è stato esportato correttamente da un altro sistema restituisce cannot import 'tank': pool may be in use from other system; sudo zpool import -f tank forza l'operazione dopo aver verificato che nessun altro host lo utilizzi.

modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... su Debian dopo un aggiornamento del kernel. DKMS non ha compilato il modulo per il nuovo kernel, di solito perché non sono installati gli header corrispondenti. dkms status mostra quale modulo è stato compilato per ciascun kernel. sudo apt install -y linux-headers-$(uname -r) esegue quindi sudo dkms autoinstall per ricompilarlo e sudo zpool import tank ripristina il pool.

Il pool è pieno, ma hai eliminato i file. I dati eliminati restano sul disco finché uno snapshot continua a farvi riferimento; per questo du e df mostrano valori diversi. zfs list -o space -r tank suddivide l'utilizzo in USEDDS e USEDSNAP, e un valore elevato di USEDSNAP indica la causa. Elimina i vecchi snapshot con sudo zfs destroy tank/data@2026-06-01 per recuperare lo spazio.

I conteggi CKSUM aumentano in zpool status. Un componente sottostante a ZFS ha restituito dati non validi. Su un mirror, il conteggio è un avviso e il blocco è stato riparato. In un pool con un solo disco, il file è perso; zpool status -v ne indica il nome. Ripristina quel file da un backup che non si trova in questo pool.

Il server è lento e utilizza lo swap. Limita ARC come indicato sopra, quindi esegui arc_summary e controlla il rapporto di hit. Se ARC è troppo piccolo per contenere il working set, ogni lettura viene eseguita dal disco. In questo caso un filesystem tradizionale che utilizza la page cache offrirebbe prestazioni migliori.

FAQ

Quanta RAM richiede ZFS su un VPS?

ZFS funziona su un'istanza da 2 GB. La domanda reale è quanta memoria resta disponibile per l'applicazione. Senza ottimizzazioni, OpenZFS 2.3 consente ad ARC di crescere fino al maggiore tra RAM meno 1 GiB e 5/8 della RAM; quindi, su una macchina da 4 GB, la cache può utilizzare 3 GiB. Impostare zfs_arc_max su un valore che il carico di lavoro può riservare, quindi verificarlo leggendo la riga c_max da /proc/spl/kstat/zfs/arcstats.

Uno snapshot ZFS è un backup?

No. Uno snapshot risiede nello stesso pool dei dati. Sopravvive a un rm errato e a un aggiornamento non riuscito, ma viene perso se si perde il pool o l'istanza. Per trasformarlo in un backup, inviarlo a un'altra macchina con zfs send oppure usare uno strumento di backup che scriva su uno storage non controllato da questo server.

ZFS funziona nello stesso modo su FreeBSD e Linux?

La codebase è la stessa da OpenZFS 2.0, rilasciato a dicembre 2020; anche i comandi e il formato su disco sono gli stessi, e i pool possono essere spostati tra i due sistemi. La differenza riguarda il packaging. FreeBSD include ZFS nel sistema base. Su Linux ogni distribuzione decide come gestirlo: Ubuntu compila il modulo nei propri pacchetti del kernel, mentre Debian lo compila sulla macchina tramite DKMS. Di conseguenza, un aggiornamento del kernel può lasciare il sistema senza modulo finché la ricompilazione non viene completata.

ZFS può riparare la corruzione su un VPS con un solo disco?

Rileva la corruzione e identifica il file, ma non può ripararla, perché per la riparazione serve una seconda copia del blocco. zfs set copies=2 su un dataset fornisce questa seconda copia al doppio dello spazio e gestisce un blocco danneggiato, ma non la perdita di un volume. Un mirror su due volumi è la soluzione che consente una riparazione effettiva.

La compressione rallenta il server?

lz4 di solito lo rende più veloce. I blocchi compressi richiedono meno byte scritti e letti, mentre il costo CPU per blocco è ridotto rispetto al lavoro risparmiato sul disco. Impostare compression=lz4 alla radice del pool, in modo che ogni dataset erediti l'impostazione, quindi controllare zfs get compressratio tank dopo aver scritto dati reali.