Dopo tanti anni di utilizzo di FreeBSD, il passaggio ad ambienti Linux mi da sempre una sensazione di rigidità a causa di alcune funzionalità native del sistema operativo che non trovano un equivalente su Linux.
Una di queste è proprio ZFS – il filesystem nato su Solaris e rapidamente adottato da FreeBSD prima ancora che nascesse l’iniziativa OpenZFS finalizzata a rendere il progetto totalmente Open e trasversale alle implementazioni OS-dependant.
Elencare tutte le funzionalità di ZFS è al di fuori dello scopo di questo articolo, ma è utile sottolineare quali siano le funzionalità chiave che impattano sulla vita di tutti i giorni di un utente normale:
- I filesystem ZFS sono di fatto una serie di contenitori indipendenti che convivono all’interno di un contenitore virtuale di dischi definito “pool” e che può essere distribuito su più dischi in maniera trasparente.
- I pool ZFS possono implementare feature di striping/mirroring, se richiesto.
- I filesystem ZFS nascono sicuri by-design in quanto implementano un controllo di parità del dato a livello di singolo cluster di informazioni.
- I filesystem ZFS implementano una compressione dei dati trasparente tramite vari algoritmi.
- I filesystem ZFS implementano gli snapshot in maniera nativa, trasparente e consultabile (possiamo fare uno snapshot del filesystem in tempo reale senza interromperlo e possiamo anche navigare nello snapshot – ed ad esempio copiare file dallo snapshot ad altrove – mentre la versione online continua a lavorare indisturbata)
- Ogni filesystem ZFS implementa un set completo di parametri configurabili, e modificabili in tempo reale senza bisogno di attività “retroattive” – ad esempio possiamo avere un filesystem già pieno, impostare a caldo la compressione e tutte le nuove scritture da questo momento in poi verranno effettuate in maniera compressa creando una transizione di fatto trasparente.
- Allo stesso modo, il pool ZFS all’interno del quale vengono allocati i filesystem può essere allargato, spostato, ridimensionato, riconfigurato in maniera quasi sempre trasparente per le attività dei filesystem in esso contenuti.
- I pool ZFS ed il filesystem ZFS nascono con un approccio “zero-configuration” – questo è uno dei concetti che più mi ha confuso nella fase iniziale: non troverete mai riferimenti ad un disco, ad un pool o ad un filesystem all’interno di file quali l’/etc/fstab: tutti i metadati informativi relativi ai pool ed ai filesystem vengono salvati (in molteplici copie) sui dischi, permettendo a ZFS di ricostruire in tempo reale la mappa topologica dello storage, associando i dischi, importando i pool, e rimontando i filesystem dove atteso.
- Ultima, anche se non realmente “visibile”, grande differenza risiede nell’approccio Copy-on-Write del filesystem che di fatto garantisce che il filesystem ZFS sia sempre, by design, in uno stato consistente: i dati non vengono mai modificati su disco, ma sempre riscritti nella versione aggiornata – mai più filesystem corrotti!
Recentemente una macchina Debian ospitante un database PostgreSQL aveva finito lo spazio su uno storage di tipo ext4 ed ho cercato di capire se si potesse cambiare il paradigma per migliorare le cose.
La principale cosa a cui prestare attenzione consiste nel fatto che ZFS non può essere incluso nella distribuzione del Kernel Linux per questioni di incompatibilità tra la licenza GPL 2 di Linux e la CDDL di OpenZFS, pertanto è necessario effettuare in maniera esplicita l’installazione del modulo ZFS sulla macchina Debian. Il processo è comunque molto facile richiede solo di prestare attenzione al fatto che il kernel installato ed il kernel in esecuzione siano allineati al momento dell’installazione di ZFS.
Iniziamo con creare una nuova VM su cui effettuare la nostra installazione di prova – ad esempio una macchina B1.4×8 in ambiente IBM Cloud: 4CPU per 8 GB di RAM, con un profilo Minimal Install di Debian 12.x Bookworm. Nel suo setup iniziale la macchina ha solo il base volume da 25GB.
Come primo passaggio effettuiamo un aggiornamento dell’intera macchina all’ultima release software con particolare attenzione al kernel in esecuzione e quelli installati.
# apt update
[...]
# apt upgrade
[...]
# uname -a
Linux testZFS 6.1.0-21-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.90-1 (2024-05-03) x86_64 GNU/Linux
# ls -l /boot/initrd.img-6.1.0-*
-rw------- 1 root root 41966363 Dec 29 15:11 /boot/initrd.img-6.1.0-18-amd64
-rw------- 1 root root 44237625 Dec 29 15:12 /boot/initrd.img-6.1.0-21-amd64
-rw------- 1 root root 44271678 Dec 29 15:20 /boot/initrd.img-6.1.0-28-amd64
In questo caso il kernel in esecuzione non corrisponde all’ultima versione installata, sarà quindi opportuno effettuare un riavvio della macchina per assicurarsi che le due cose coincidano prima installare i nuovi moduli.
# reboot
Broadcast message from root@testZFS on pts/1 (Sun 2024-12-29 15:25:03 CET):
The system will reboot now!
root@testZFS:~# Connection to testZFS closed by remote host.
Connection to testZFS closed.
Per installare OpenZFS è necessario installare i repository esterni “contrib” di Debian, per poi effettuare un update dei repository ed installare i pacchetti relativi agli header del kernel ed a ZFS.
# sed -r -i'.BAK' 's/^deb(.*)$/deb\1 contrib/g' /etc/apt/sources.list
# apt update
# apt install linux-headers-amd64 zfsutils-linux zfs-dkms zfs-zed
[...]
zfs.ko:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/6.1.0-28-amd64/updates/dkms/
[...]
# modprobe zfs
# zfs version
zfs-2.1.11-1
zfs-kmod-2.1.11-1
È giunto il momento di aggiungere un nuovo disco alla macchina.
# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sr0 11:0 1 1024M 0 rom
xvda 202:0 0 25G 0 disk
├─xvda1 202:1 0 1G 0 part /boot
└─xvda2 202:2 0 24G 0 part /
xvdb 202:16 0 2G 0 disk
└─xvdb1 202:17 0 2G 0 part [SWAP]
xvde 202:64 0 500G 0 disk
xvdh 202:112 0 64M 0 disk
Procediamo con la creazione di un nuovo pool che chiameremo pgDatas
# zpool create pgDatas /dev/xvde
# zpool status
pool: pgDatas
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
pgDatas ONLINE 0 0 0
xvde ONLINE 0 0 0
errors: No known data errors
La creazione di un Pool ZFS implica la creazione del Filesystem ZFS principale al suo interno. È possibile aggiungere altri filesystem dentro al primo (ed altri dentro ai secondi), tenendo presente che, se non esplicitamente impostate in maniera diversa, i filesystem figli erediteranno le caratteristiche di quello principale. Possiamo quindi chiedere l’elenco dei FileSystem presenti, la lista dei possibili parametri di configurazione e modificare a caldo alcuni dei parametri di configurazione.
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
pgDatas 118K 481G 24K /pgDatas
# zfs get all
NAME PROPERTY VALUE SOURCE
pgDatas type filesystem -
pgDatas creation Sun Dec 29 15:48 2024 -
pgDatas used 118K -
pgDatas available 481G -
pgDatas referenced 24K -
pgDatas compressratio 1.00x -
pgDatas mounted yes -
pgDatas quota none default
pgDatas reservation none default
pgDatas recordsize 128K default
pgDatas mountpoint /pgDatas default
pgDatas sharenfs off default
pgDatas checksum on default
pgDatas compression off default
pgDatas atime on default
[...]
# zfs set compression=lz4 pgDatas
# zfs set atime=off pgDatas
# zfs set recordsize=16k pgDatas
Abbiamo quindi attivato la compressione LZ4 sul filesystem, disattivato l’atime ed impostato la dimensione dei cluster a 16Kb, valore consigliato per un filesystem dedicato a PostgreSQL che scrive dai a blocchi di 8Kb per volta (per maggiori informazioni).
Ultimo passaggio fondamentale e spesso tralasciato è quello di modificare le impostazioni dell’ARC di ZFS. L’ARC rappresenta la cache dinamica con cui ZFS gestisce l’accesso e la scrittura su disco. ZFS su Linux di default lascia la gestione dell’ARC totalmente automatica – nella mia esperienza questo è raramente ciò che ci aspettiamo, specialmente su un server che è dedicato ad altre attività. Per configurare l’ARC su Linux è necessario modificare il file /etc/modprobe.d/zfs.conf aggiungendo le seguenti impostazioni:
# Set Max ARC size => 2GB == 2147483648 Bytes
options zfs zfs_arc_max=2147483648
# Set Min ARC size => 1GB == 1073741824
options zfs zfs_arc_min=1073741824
Chiaramente questi parametri possono essere tarati in base alla memoria presente a sistema, sia tramite il comando arc_summary che permette di sapere quale sia il pattern di utilizzo dell’ARC, sia osservando l’uso della memoria sulla macchina Linux. A questo punto riavviamo la macchina sia per verificare che abbia preso le impostazioni dell’ARC sia per verificare che il filesystem ZFS sia correttamente rimontato al boot.
# mount | grep -i zfs
pgDatas on /pgDatas type zfs (rw,noatime,xattr,noacl)
# cat /sys/module/zfs/parameters/zfs_arc_min
1073741824
# cat /sys/module/zfs/parameters/zfs_arc_max
2147483648
# arc_summary
------------------------------------------------------------------------
ZFS Subsystem Report Sun Dec 29 16:10:50 2024
Linux 6.1.0-28-amd64 2.1.11-1
Machine: testZFS (x86_64) 2.1.11-1
ARC status: HEALTHY
Memory throttle count: 0
ARC size (current): 0.2 % 3.2 MiB
Target size (adaptive): 50.0 % 1.0 GiB
Min size (hard limit): 50.0 % 1.0 GiB
Max size (high water): 2:1 2.0 GiB
A questo punto possiamo iniziare a riempire il FileSystem. Ogni tanto possiamo controllare l’efficienza della compressione dei dati stessi chiedendo una delle metriche di ZFS denominata compressratio:
# zfs get compressratio
NAME PROPERTY VALUE SOURCE
pgDatas compressratio 3.57x -
Ultimo comando che può esserci utile è quello per aggiungere un secondo disco che si affianchi al primo come stripe secondario. Trattandosi di VM Cloud infatti i dischi sono già replicati dal Cloud Provider e quindi l’unico obiettivo che abbiamo è quello di massimizzare lo spazio disponibile ed il parallelismo di scrittura sulle device virtuali. Abbiamo quindi aggiunto un disco /dev/xvdc alla macchina e potremo aggiungerlo al Pool ZFS.
# zpool status pgDatas
pool: pgDatas
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
pgDatas ONLINE 0 0 0
xvde ONLINE 0 0 0
errors: No known data errors
# zpool add pgDatas /dev/xvdc
# zpool status
pool: pgDatas
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
pgDatas ONLINE 0 0 0
xvde ONLINE 0 0 0
xvdc ONLINE 0 0 0
errors: No known data errors
# df -h /pgDatas
Filesystem Size Used Avail Use% Mounted on
pgDatas 962G 134G 828G 14% /pgDatas
Buon divertimento!

Leave a comment