https://arstechnica.com/information-technology/2020/05/zfs-101-understanding-zfs-storage-and-performance/
https://unixdigest.com/articles/battle-testing-zfs-btrfs-and-mdadm-dm.html
https://openzfs.org/wiki/Newcomers
https://openzfs.github.io/openzfs-docs/Project%20and%20Community/FAQ.html
https://blog.victormendonca.com/2020/11/03/zfs-for-dummies/
https://www.reddit.com/r/zfs/
Généralités
ZFS est une architecture qui combine des fonctionnalités de gestion de volumes, et de système de fichiers.
Recommandé de conserver au moins ~10% d’espace libre (ou 500Go, le + petit des 2 devrait être ok) dans le pool pour éviter de sérieusement dégrader les performances.
Architecture
Le plus gros ensemble sous ZFS s’appelle un zpool. Il est constitué de 1 ou plusieurs vdevs, chaque vdev étant constitué d'1 ou plusieurs périphérique (disque physique, fichier etc).
Une fois crée, le zpool peut directement être monté en tant que système de fichier, mais il est aussi possible d’y créer des dataset, qui peuvent eux-même être montés.
On peut aussi créer un dataset enfant sous un dataset parent, avec la possibilité d’hériter des propriétés du parent.
On peut également créer des zvol (volumes) au sein d’un zpool, qui pourra être accédé comme un périphérique bloc : il sera possible de le formater avec un autre FS.
Considérations sur la structure d’un pool et son évolution :
https://openzfs.github.io/openzfs-docs/Basic%20Concepts/Pool%20Structure/Changing%20Pool%20Layout.html
Globalement, en cas de RAIDZ, il sera impossible de retirer un vdev (même non-raidz) du pool.
ARC
https://openzfs.github.io/openzfs-docs/Basic%20Concepts/Pool%20Structure/Caching.html
ZFS fait une utilisation assez intensive des caches, si disponibles.
Il y a un cache primaire de lecture en RAM, le ARC (Adaptive Replacement Cache).
On peut définir un ARC de 2nd niveau sur disque rapide (L2ARC). Il consomme aussi de la RAM, donc si on a des limites basses de RAM, il peut être contre-productif (le RAC sera plus petit pour laisser la place à l’indexation du L2ARC). À la grosse louche, environ 1G de RAM pour 30G de L2ARC (mais ça dépend du recordsize de chaque fichier).
Voir plus bas.
ZIL
ZFS Intent Log
C’est l’endroit où sont écrites les demandes d’écriture synchrones.
Par défaut, ce sont des blocs du pool ; mais on peut définir un vdev spécial dans ce but (le SLOG (Separating Intent Log), type log).
Il faut de la protection (Power-loss Protection, redondance etc) sinon des données seront perdues.
special
https://openzfs.github.io/openzfs-docs/Basic%20Concepts/Pool%20Structure/Special%20vdev.html
vdev qui va stocker certains données spéciales ; notablement les metadonnées.
Permet de grandement limiter les random IO dans le cas de disques HDD si on met les metadonnées sur un SSD.
Attention, perdre un special vdev équivaut à perdre le pool entier !
Si le pool contient au moins un RAIDZ, il est impossible de retirer le vdev special ; il sera donc définitif.
En d’autres cas, il devrait être possible de supprimer un vdev special après son ajout.
Install
Recommandé de l’installer depuis les backports
Besoin de la section contrib
sudo apt install -t stable-backports zfsutils-linux zfs-dkms
Il y a aussi le paquet zfs-initramfs
Nécessaire pour avoir un /boot ou un / en ZFS ?
zpool
C’est un ensemble logique complet pouvant être utilisé avec ZFS. Il est constitué de 1 ou plusieurs vdev.
Au sein d’un zpool, les données sont réparties entre les différents vdev de stockage (ou de support).
Il n’y a pas de redondance au sein d’un zpool : si un seul vdev vient à manquer, l’ensemble du zpool est perdu !
C’est au sein de chaque vdev que l’on va s’assurer d’une redondance si nécessaire.
Le zpool contient directement un dataset, qui peut être monté. Il est aussi possible d’y créer des dataset enfants et sous-enfants.
Il y a un héritage des propriétés (qui peut être modifié).
vdev
Un vdev représente une unité de stockage, au sein du zpool.
Il y’a plusieurs types de vdev, etre autres :
- ceux de stockage, qui peuvent être en simple disque, en mirror (équivalent RAID1), en RAID-Z (équivalent RAID5-6)
- ceux de support :
- CACHE
- LOG
- SPECIAL
device
Peuvent être des périphériques blocs ou des fichiers.
dataset
Représente un ensemble de données, géré comme une unité.
C’est au niveau du dataset que sont gérés les snapshots
Bien que ce ne soit pas exactement la même chose, ça s’approche des subvolumes de btrfs.
snapshot
clone
ashift
ashift représente la taille de secteurs des disques d’un pool, en puissance de 2.
9 : 2⁹ = 512
12 : 2¹2 = 4096
9 peut être intéressant pour les vieux HDD en addressage logique et physique 512, mais sinon 12 sera sûrement plus adapté et performant.
Si on ne le spécifie pas, il est détecté automatiquement. Mais il est possible que la détection soit incorrecte, notamment avec les disques 512e.
On peut la spécifer avec
zpool create -o ashift=12
Pour la vérifier, on peut faire :
zdb -C | grep ashift
ou
zpool get ashift
Il y a aussi la commande
zpool get ashift mypool all-vdevs
qui donne le ashift de chaque vdev sous-jacent ; mais celui-ci n’a pas d’importance ; il changera si le pool est exporté puis importé. Il définit juste le niveau d’ashift qui sera utilisé pour l’autodétection si on crée un vdev dessus.
https://github.com/openzfs/zfs/issues/16838
Commande zpool
Permet de gérér les pools et les vdev.
Les vdev sans chemin absolu sont cherchés dans /dev/
Création d’un pool
man zpool create
De la forme
poolname = "myzpool"
sudo zpool create -m mountpoint $poolname dev1 dev2 [redundancy] dev3 dev4 [redundancy] dev5 dev6 dev7
On peut spécifier une nature de redondance pour chaque vdev, puis on spécifie les devices (ou fichiers) qui entreront dans ce vdev.
Dans le cas ci-dessus, nous aurons 4 vdev : dev1, dev2, une redondance entre dev3 et dev4, et une redondance entre dev5, dev6 et dev7.
Nous aurons probalement un message d’erreur nous informant que la redondance n’est pas régulière entre les différents vdev.
La redondance peut prendre entre autres ce valeurs : mirror , raidz (équivalent à raidz1) , raidz2 , raidz3.
Le zpool est importé/monté dans le système dès sa création.
Cas simple : un seul périphérique :
sudo zpool create $poolname /dev/disk/by-id/ata-XXX
Note il est conseillé de choisir une méthode + fiable que /dev/sdX pour définir les vdev, car en cas de changement de lettre, il faudra supprimer le fichier /etc/zfs/zpool.cache (ou exporter la pool) puis réimporter la pool.
Paramètres à la création
Lors de la création d’un pool, certains paramètres sont choisis définitivement.
Les principaux à mentionner me semblent être ashift et le chiffrement.
D’autres paramètres peuvent être changés par la suite, mais la modification n’affecte pas les données déjà existantes. Par exemple, la compression, ou le recordsize.
Lister les pools
zpool status
Les chiffres READ WRITE et CKSUM comptent le nombre d’erreurs de chaque catégorie sur chaque vdev.
Sortir les données en json :
zpool status -j | jq
donne beaucoup d’infos détaillés sur chaque composant.
man zpool status
Beaucoup d’options intéressantes
-s : pour identifier les vdev lents
zpool list -v -P
Permet de voir l’usage disque de chaque pool et même de chaque vdev.
Historique des commandes
zpool history
Permet de voir l’historique des commandes ayant agi sur ce zpool
zpool attach / detach
zpool attach $poolname device new_device
permet d’ajouter un disque/fichier à un device.
S’il s’agit d’un miroir ou directement d’un disque, le disque sera ajouté en tant que miroir.
S’il s’agit d’un RAIDZ, le RAIDZ est agrandi en prenant en compte le nouveau disque, et en conservant son niveau fonctionnel (un raidz2 reste un raidz2, mais avec 1 disque en plus.
Pour ça, l’ensemble des données est réécrite sur le raidz
sudo zpool detach $poolname device
Permet de supprimer un disque d’un miroir ou d’un “replacing-X”.
Pool suspendu
Si un vdev vient à manquer, le pool est suspendu.
S’il est encore disponible (par exemple un disque qui a été déconnecté mais qui fonctionne correctement), il devrait de le rebrancher, puis d’entrer la commande
sudo zpool clean $poolname
ça devrait “resynchroniser” le pool, et remettre le compteur d’erreurs à 0 partout.
Dans mon expérience, même en déconnectant un disque en plein milieu d’une copie de fichier vers le pool, si on le reconnecte et que l’on cleane, le transfert se finit correctement et le fichier ne sera pas corrompu.
À condition que le chemin du device soit le même que précédemment ! D’où l’intérêt d’utiliser des chemins fixes (by-id).
Si le vdev est définitivement perdu, il ne sera pas possible de récupérer les données du pool.
Lister les propriétés d’une pool
zpool get all $poolname
ou plus finement
zpool get property1,property2 $poolname
Ajouter un vdev à une pool
zpool add $poolname device
Détacher une pool
sudo zpool export $poolname
Trouver et importer des pools inactives
sudo zpool import
va lister les pools détectés (et inactifs)
Par défaut, ça va chercher sur les périphériques dispos dans /dev/. Les informations concernant l’appartenance à un pool sont trouvées dans la table de partition du périphérique.
On peut spécifier un dossier ou device à chercher avec l’option -d. Nécessaire pour importer un pool créé sur des fichiers.
sudo zpool import $poolname [newpoolname]
Permet de la rendre disponible, éventuellement en changeant son nom.
Détruire (et tenter de restaurer) un pool
zpool destroy $poolname
Ceci essaye de démonter tous les datasets, puis détruit le pool (avec tous les datasets contenus). Aucune confirmation n’est demandée.
Ceci permet d’utiliser les disques qui étaient dans le pool pour un autre usage.
Cette suppression supprime les métadonnées du pool, mais les données restent intactes (tant qu’on n’écrit pas dessus).
Si la destruction est une erreur, on peut lister les pools supprimés avec :
zpool import -D
et si c’est bon, on peut les importer automatiquement avec
zpool import -a -D
Santé et remplacement d’un RAIDZ-2
Dans cet exemple, j’ai un pool constitué d’un seul vdev, lui-même constitué de 8 fichiers en RAIDZ-2.
J’ai volontairement corrompu ce vdev en supprimant 2 fichiers.
Lorsque l’on liste les pools et les vdev, le pool ainsi que le vdev se trouvent dans l’état DEGRADED.
Chacun des 2 devices (en l’occurence fichiers) se trouve dans l’état FAULTED.
FAULTED signifie que le device sous-jacent est toujours pris en compte dans le vdev, mais inaccessible ou défectueux (par exemple disque en panne, ou débranché, ou fichier supprimé).
Il y a aussi l’état OFFLINE, qui signifie que le device sous-jacent a été sorti du vdev, qui est en attente d’un remplacement pour ce device.
On peut volontairement passer un device en OFFLINE avec la commande :
sudo zpool offline $poolname device
Lorsqu’un device est sain (“ONLINE”), son nom/chemin est indiqué dans la sortie de zpool status ou zpool list -v -P.
Lorsqu’un device est absent (FAULTED ou OFFLINE), ce sera son GUID qui sera indiqué.
On peut obtenir les GUID de tous les device, même les sains, avec zpool list -v -P -g.
Pour remplacer une disque/fichier offline ou faulted :
sudo zpool replace $poolname $oldGUID /dev/sdX
sudo zpool replace $poolname $oldGUID ./file.dat
Ça devrait automatiquement lancer un resilvering. Pendant ce temps, un device replacing-1 apparaît dans le vdev, qui a lui-même son propre GUID et est composé de l’ancien et du nouveau device.
Il peut y avoir l’erreur cannot replace OLD_GUID with sdX: sdX is busy
J’ai eu ça en essayant de réajouter un disque qui avait déjà fait partie du pool. Même après wipefs -af sur les partitions puis sur la table de partition, le disque restait “busy”.
J’ai résolu l’erreur en réinitialisant le SSD comme ceci
Je suppose qu’en écrivant l’ensemble du SSD avec des 0 ça peut fonctionner aussi.
ESSAYER zpool labelclear
Commande zfs
Sert à gérer les datasets.
Monter un dataset
zfs mount $poolname
va monter dans le chemin défini dans la propriété mountpoint
Lister les montages ZFS
zfs mount
Lister les propriétés des datasets
zfs get all [mydataset]
ou + finement
zfs get property1,property2 [mydataset]
Les propriétés dont la source est “default” sont définies à la volée, selon les valeurs par défaut (par exemple, le mountpoint sera /datasetname).
Les propriétés définies explicitement sur le dataset auront comme source “local”, et font partie intégrante du dataset, mêem si celui-ci est branché sur une autre machine.
zfs list
man zfs list
zfs list -t all -r
Définir des propriétés des datasets
sudo zfs set property=value mypool/mydataset
On peut aussi enlever une valeur explicite et remettre par défaut avec la commande
sudo zfs inherit property mypool/mydataset
ARC
https://openzfs.github.io/openzfs-docs/Basic%20Concepts/Pool%20Structure/Caching.html
Le cache ARC est un mécanisme de mise en RAM de certaines données ; notamment les données très récentes et les données fréquemment accédées.
La quantité max octroyée au cache ARC dépend de la quantité de RAM mais peut être assez élevée.
Pour voir la quantité max et la quantité utilisée, on peut passer par htop en customisant l’affichage.
zarcsummary
zarcstats
Sinon on peut voir le max avec
cat /proc/spl/kstat/zfs/arcstats | grep c_max
et la quantité actuellement utilisée avec
cat /proc/spl/kstat/zfs/arcstats | grep -E "^size"
Il faut diviser les valeurs par (1024³) pour avoir les valeurs en Go, et (1024²) pour avoir les valeurs en Mo.
Activer ou désactiver ARC
Cette fonctionnalité peut être désactivée pour certains dataset si nécessaire (utile par exemple pour des tests de perf fio).
On peut vérifier le statut d’activation du cache avec :
zfs get all | grep -i primarycache
et le désactiver avec
sudo zfs set primarycache=none monpool/fio-test
ou le réactiver avec
sudo zfs set primarycache=all monpool/fio-test
ou par défaut avec
sudo zfs inherit primarycache monpool/fio-test
L2ARC
Le cache ARC de niveau 2 est un device spécial (typiquement un SSD), qui n’est pas obligatoire, et dans lequel se déverse le cache RAM qui devient trop vieux.
Pour voir si on en a un, il faut regarder la sortie de
zpool status
et voir si un device cache est mentionné.
On peut aussi faire
cat /proc/spl/kstat/zfs/arcstats | grep l2_size
pour avoir la taille en octet.
Si on souhaite le désactiver, essayer comme ci-dessus avec secondarycache au lieu de primarycache.
RAIDZ
Le RAIDZ est un système de parité analogue au RAID (bien que fonctionnant différemment).
Le RAIDZ-1 contient 1 disque de parité (analogue au RAID5). Le RAIDZ-2 contient 2 disques de parité (analogue au RAID6).
Il existe aussi le RAIDZ-3 avec 3 disque de parité.
ZFS peut aussi fonctionner en mode miroir (analogue au RAID1), cette fonctionnalité est simplement appelée “mirror”.
Deduplication
Permet d’économiser de l’espace de stockage lorsque l’on stocke plusieurs fois des blocs de données identiques.
Nécessiter beaucoup de ressources : beaucoup de RAM, et il est conseillé d’avoir des SSD dédiés pour stocker la table de dédup (DDT).
Globalement il n’est pas conseillé de l’activer, sauf cas spécifiquement adapté.
Overhead
https://wintelguy.com/2017/zfs-storage-overhead.html
L’espace “slop space” est réservé par le FS pour être sûr d’avoir de la place pour certaines opérations critiques, même en cas de saturation du stockage.
Par défaut il devrait être à 1/32e du stockage total.
scrub :
CoW et VMs
Le CoW crée une légère baisse de perf, qui peut vraiment s’amplifier pour des fichiers avec des écritures fréquentes, comme les VMs ou les BDD
voir pour désactiver CoW pour certains fichiers/dossiers/volumes ?