ZFS, vous connaissez ? Vous devriez !

Christian Quest
8 min readOct 26, 2019

--

Que diriez vous d’un filesystem permettant, entre autres :

  • la gestion des disques physiques et de la redondance
  • le contrôle d’intégrité des données stockées
  • la compression transparente
  • la gestion de caches à plusieurs niveaux
  • les snapshots (y compris en read-write)
  • des synchronisations rapides de répliques
  • la déduplication de données pour optimiser le stockage
  • le chiffrement
  • des alertes automatiques sur son état

Tout cela est intégré aujourd’hui dans ZFS qui fête ses 14 ans, mais est encore bien peu connu des dev, devops et sysadmin… mais commence à faire son chemin, en particulier du côté d’Ubuntu.

Une des raisons est sûrement une adolescence tumultueuse.
Créé à l’origine par SUN Microsystems à partir de 2001, il est lancé officiellement au sein de Solaris en octobre 2005 et son code est ouvert… puis, malheureusement, les choses se gâtent.
Comme beaucoup de projets opensource, ZFS subit le rachat de SUN par Oracle en 2010 qui ne publie plus les mises à jour du code.
Comme ses cousins java, MySQL et OpenOffice, pour que ceci s’arrange et ne plus dépendre d’Oracle, il a fallut faire un fork, dans notre cas OpenZFS qui depuis a fait entrer ZFS dans l’age adulte.

ZFS est aujourd’hui disponible sur les OS Unix-like: FreeBSD, NetBSD, Linux, macOS, Solaris/Illumnos, etc. Il n’y a que la version Windows qui manque.

L’autre raison de l’attentisme face à ZFS (sous Linux) est peut être son numéro de version… 0.8.x qui peut laisser penser à quelque-chose d’inabouti alors qu’il n’en est rien comme on va le voir !

ZFS sur Linux

Je n’ai utilisé ZFS que sous Linux (Debian/Ubuntu) et directement comme module d’extension du kernel et intégré nativement à l’OS. Au préalable un premier portage avait été fait via FUSE qui forcément limitait les possibilités et les performances. Si ZFS n’est pas directement intégre au kernel Linux, c’est uniquement pour une raison de licence et pas pour des raisons techniques ou de maturité.

Plus qu’un file-system: un système de stockage

On voit à la liste des fonctionnalités que ZFS dépasse les limites courantes d’un simple système de fichiers. Pour obtenir une liste équivalente sous Linux avec un file-system classique comme l’habituel ext4, il faudrait faire appel à des briques supplémentaires telles que lvm (gestion des disques physiques, snapshots), mdadm (redondance), luks (chiffrement), bcache (caches), etc.

Même avec l’ensemble de ses briques, des fonctionnalités essentielles de ZFS ne sont toujours pas au rendez-vous et l’interaction de ces briques aporte une complexité qui rime avec instabilité.

Pool !

ZFS se base sur un “pool”, qui est en général un ensemble de disques qui peuvent servir à stocker les données de façon pérenne ou temporaire (cache).

Il faut le voir comme un grand espace de stockage, non dédié, dans lequel ZFS va piocher pour stocker des données. Un même pool peut ainsi servir à allouer plusieurs filesystems, voire à allouer des volumes en mode bloc comme on le ferait avec des partitions.

Redondance

Lorsque l’on a plusieurs disques on peut les agréger entre eux pour ajouter de la redondance et sécuriser les données en cas de panne totale ou partielle d’un disque. Ces grappes de disques sont appelées “vdev” dans le jagon ZFS.

Plusieurs niveaux de redondance sont possibles, de nulle (stripping) aux miroirs multiples en passant par les habituels niveaux de RAID… 1, 5, 6, 10, etc.

Pour créer par exemple un pool avec 8 disques dont deux en redondance, cela se fait très simple en ligne de commande :

zpool create poupoule raidz2 sd[abcdefgh]

On aurait pu aussi les organiser en 2 grappes de 4 disques contenant chacun 1 disque en redondance:

zpool create poupoule raidz sd[abcd] raidz sd[efgh]

Un pool de stockage peut s’étendre très facilement… ajoutons 4 autre disques avec 1 disque redondant:

zpool add poupoule raidz sd[ijkl]

4 choix de redondance sont possibles pour ces grappes: raidz (1 pour N), raidz2 (2 pour N), raidz3 (3 pour N), mirror (N pour 1)

Attention… pour l’instant ZFS ne permet pas de retirer des disques de stockage d’un pool sauf pour les grappes en “mirror”.

Un dernier élément en faveur de l’intégrité des données, est l’ajout possible (et recommandé) dans un pool d’un volume rapide dédié au journal d’écriture.

On peut l’ajouter (et le retirer) après coup, comme ici avec un SSD NVMe dédié à cette tâche:

zpool add poupoule log nvme0n1

Ce volume n’a pas besoin d’être important, quelques Go suffisent.

Performance : les caches

Pour améliorer les performances en lecture, ZFS gère son propre cache en RAM pour limiter les accès aux disques, c’est le ARC (Adaptative Replacement Cache).

Ce cache de premier niveau conserve un mix entre les données les plus récentes et les données les plus fréquemment utilisées. Ceci évite qu’une lecture d’un gros fichier n’élimine du cache des données pourtant souvent utilisées et améliore très nettement son efficacité.

Un second niveau de cache est possible, c’est le L2ARC (Level 2 ARC), une extension du ARC mais stockée typiquement sur un SSD, qu’on pourra ajouter avec:

zpool add poupoule cache nvme0n2

Comme le log, on peut l’ajouter ou le retirer après la création du pool. Il ne conserve temporairement qu’une copie des données et sa disparition n’impacterait pas les données stockées dans le pool.

Et ZFS sur un seul disque ?

Oui, c’est possible, ZFS peut aussi être utilisé avec un unique disque, avec une partition sur un disque, voire même au sein d’un (gros) fichier unique (idéal pour faire des tests).

Par exemple pour tester ZFS sur un fichier :

fallocate -l 16G poupoule.zfs
zpool create poupoule poupoule.zfs

Dans ce cas pas de redondance… quoique, on peut demander à ZFS de tout enregistrer 2 fois (ditto) ce qui évitera un problème en cas de secteurs défectueux, mais pas en cas de panne totale du disque.

Ceci permet tout de même de bénéficier des autres fonctionnalités de plus haut niveau de notre liste du début car nous n’avons vu que 2 items: la redondance et les caches !

Le pool c’est cool !

Créer un filesystem sur un pool zfs est très simple:

zfs create poupoule/monfs

Par défaut, il est monté sur /poupoule/monfs mais ceci est modifiable.

Activons la compression transparente:

zfs set compression=lz4 poupoule/monfs

Désormais, les fichiers qui seront créés dans ce filesystem seront compressés à l’aide de l’algorithme lz4 qui fera gagner de l’espace de stockage et par la même occasion réduira le nombre d’I/O. Même si le processeur est sollicité, le gain est positif sur les performances globales en terme de débit de lecture/écriture.

Un autre gain d’espace de stockage est possible en activant la déduplication.

zfs set dedup=on poupoule/monfs

A chaque écriture d’un bloc de données, ZFS va désormais vérifier à l’aide d’une clé de hachage si un bloc identique est déjà stocké. Cette fonctionnalité nécessite de maintenir une table des clés de hachage qui occupera de la RAM. Il ne faut l’activer que si l’on a suffisamment de fichiers en doublon car cette RAM ne sera plus disponible pour le cache de lecture (ARC). Les écritures seront aussi beaucoup plus lentes !

Checksums et scrub

Par défaut, les checksums sur les données et métadonnées sont activés.

Il permettent de garantir l’intégrité des données lorsqu’elles sont relues. ZFS va ainsi vérifier à chaque lecture si une erreur s’est glissée quelque part et dans le cas d’un pool avec redondance, ira lire automatiquement une autre copie des données tout en remplaçant la copie erronnée.

Comme on le voit, l’intégrité des données est vraiment dans l’ADN de ZFS !

On peut forcer une vérification de l’ensemble du pool:

zpool scrub poupoule

Elle se fait en tâche de fond, et corrigera toute erreur rencontrée.

Bien que non prioritaire, ce contrôle va générer un grand nombre d’I/O et l’idéal consiste à le lancer régulièrement aux heures creuses, par exemple la nuit avec un cron, puis de la mettre en pause en fin de nuit avec:

zpool scrub -p poupoule

Alarme !

Pour être informé en cas d’erreur (erreur détectées dans un scrub ou à l’usage, disque physique indisponible ou présentant des problèmes), ZFS possède un démon dédié qui pourra envoyer un email à l’administrateur. C’est ZFS Event Daemon ou “zed”.

Chiffrement

Depuis peu la version Linux de ZFS intègre le support du chiffrement. Les données sont chiffrées (après compression éventuelle) avant d’être stockées.

Le chiffrement peut être activé à la création de chaque filesystem. On peut donc avoir sur un même pool des portions chiffrées ou non et avec des clés différentes.

Snapshots et clones

Les snapshots sont sûrement une des fonctionnalités les plus intéressantes, qui permet de figer un filesystem de façon quasi instantanée. C’est la nature “copy-on-write” de ZFS qui le permet, il suffit en effet à ZFS d’écrire ailleurs les nouvelles données sans libérer les précédentes.

zfs snapshot poupoule@snapshot_du_2019_10_01

On peut créer autant de snapshots que l’on veut, mais bien sûr ceci occupera de l’espace de stockage. C’est une façon très simple d’avoir l’équivalent du Time Machine introduit par Apple il y a déjà quelques années.

Le package zfs-auto-snap permet ainsi de créer des snapshots chaque heure, jour, semaine et mois en éléminant les plus anciens automatiquement.

Les snapshots sont accessibles en lecture seule, mais on peut les transformer ou créer directement des “clones” qui eux fonctionnent en lecture/écriture. Ceci permet par exemple de tester du code ou une mise à jour sur une base de données volumineuse, sans la dupliquer et sans interrompre le fonctionnement de la base en production.

Attention, un snapshot n’est pas une sauvegarde, les données ne sont pas recopiées et c’est tout leur intérêt en terme d’espace occupé et de rapidité.

Copie de snapshot avec send et recv… une forme de sauvegarde

On peut transformer un snapshot en un flux de données, qui peut être relu pour recréer le filesystem à l’identique.

zfs send poupoule@snapshot_du_2019_10_01 > snap.file

Là où cela devient encore plus intéressant c’est qu’on peut obtenir un flux correspondant aux différences entre deux snapshots… et donc avoir un fonctionnement incrémental.

zfs send -i poupoule@ancien poupoule@nouveau > snap_increment.file

Ces copies de snapshots peuvent de plus se faire à distance… par exemple en transmettant le flux de données via ssh

zfs send -i poupoule@ancien poupoule@nouveau | ssh root@remote zfs recv

Ce mécanisme est très puissant et permet d’avoir une réplique, avec les mêmes snapshots que l’original directement utilisable (pas besoin de restaurer une sauvegarde).

Un autre avantage, c’est que chaque snapshot liste les changements intervenus depuis le précédent et n’a pas besoin de parcourir l’ensemble du filesystem pour savoir ce qui a été modifié. Sur un filesystem contenant un grand nombre de fichiers, le gain par rapport à des outils parcourant l’ensemble des fichiers et dossiers est énorme et permet de faire des réplications très fréquentes et rapidement.

Pour aller plus loin…

Ces fonctionnalités principales de ZFS mériteraint chacune plus d’approfondissement mais cet article a déjà été assez long !

D’autres choses n’ont pas été décrites comme le fonctionnement en mode bloc, qui permet de créer l’équivalent de partitions, mais avec tous les avantages procurés par le pool (redondance, caches, etc) ou les snapshots.

Un autre aspect non abordé est l’intégration de ZFS avec les couches réseau. On peut en effet directement gérer des partages NFS ou SMB pour les filesystem et iSCSI pour les volumes en mode bloc.

ZFS s’intègre très bien dans des environnements de virtualisation comme proxmox ou docker et bien entendu LXC.

--

--

Christian Quest

40 ans d'informatique + 33 de base de données + 25 d'internet + 11 de cartographie = #OpenStreetMap + #opendata + #logiciel_libre