Inhaltsverzeichnis

ZFS auf Linux ("ZFS on Linux")

ZFS ist ein von Sun Microsystems entwickeltes transaktionales Dateisystem, das zahlreiche Erweiterungen für die Verwendung im Server- und Rechenzentrumsbereich enthält. Hierzu zählen die vergleichsweise große maximale Dateisystemgröße, eine einfache Verwaltung selbst komplexer Konfigurationen, die integrierten RAID-Funktionalitäten, das Volume-Management sowie der prüfsummenbasierte Schutz vor Datenübertragungsfehlern. Der Name ZFS stand ursprünglich für Zettabyte File System.

Eine direkte Unterstützung innerhalb des Linux-Kernels ist aus Lizenzgründen problematisch (Inkompatibilität von GPLv2 und CDDL), daher gibt es momentan keine Implementierung die direkt im Kernel integriert ist. Zudem ist es (aus Sicht von ZFS) problematisch das zunehmend Kernel-Funktionen exklusiv für GPL-Software reserviert werden, die Problematik beschreibt der Artikel Linux 5.0: Lizenzkennzeichnung trifft Nvidia und ZFS on Linux.

Allerdings gibt es:

Quelle: Wikipedia.

Installation

Enthaltene Versionen von ZFS on Linux in den Distributionen

Debian11 (bullseye) + Debian 12 (bookworm)

  1. contrib aktivieren
  2. sudo apt install linux-headers-amd64 dkms --no-install-recommends # cloud-kernel: linux-headers-cloud-amd64
    sudo apt install zfs-dkms --no-install-recommends # need contrib enabled
    # not needed anymore:
    # sudo modprobe zfs
    sudo apt install zfsutils-linux

Paketquellen für bullseye mit contrib

deb http://deb.debian.org/debian bullseye main contrib
deb-src http://deb.debian.org/debian bullseye main contrib
deb http://security.debian.org/debian-security bullseye-security main contrib
deb-src http://security.debian.org/debian-security bullseye-security main contrib
deb http://deb.debian.org/debian bullseye-updates main contrib
deb-src http://deb.debian.org/debian bullseye-updates main contrib
deb http://deb.debian.org/debian bullseye-backports main contrib
deb-src http://deb.debian.org/debian bullseye-backports main contrib

Debian10 (buster)

Leider ist die Anleitung etwas dünn, die Installation von zfs-utils scheitert wenn das Kernel-modul vorher nicht geladen worden ist (nicht in debian11).

# vi /etc/apt/sources.list.d/buster-backports.list
deb http://deb.debian.org/debian buster-backports main contrib
deb-src http://deb.debian.org/debian buster-backports main contrib
# vi /etc/apt/preferences.d/90_zfs
Package: libnvpair1linux libuutil1linux libzfs2linux libzpool2linux spl-dkms zfs-dkms zfs-test zfsutils-linux zfsutils-linux-dev zfs-zed
Pin: release n=buster-backports
Pin-Priority: 990
sudo apt install linux-headers-amd64 dkms # cloud-kernel: linux-headers-cloud-amd64
sudo apt install zfs-dkms --no-install-recommends
sudo modprobe zfs
sudo apt install zfsutils-linux

Modul bei Start automatisch laden

debian 10, 11, 12

mindestens unter debian 11 wird das Modul automatisch geladen.

echo "zfs" >> /etc/modules-load.d/modules.conf

andere Systeme

echo "zfs" >> /etc/modules

Ubuntu

ab 15.10:

apt install zfsutils-linux

Ältere Versionen siehe hier.

CentOS7

Install zfs-release package:

yum localinstall --nogpgcheck http://archive.zfsonlinux.org/epel/zfs-release.el7.noarch.rpm
yum-config-manager --enable "zfs"
yum install zfs
modprobe zfs

Begriffe

ZFS Virtual Devices (ZFS VDEVs) sind meta-Devices die aus den u.g. Geräten bestehen kann. VDEVs werden dynamisch erzeugt, devices/Geräte können hinzugefügt, aber nicht entfernt werden.

Bezeichnung Bedeutung
File Dateien auf anderen Dateisystemen die als Quelle dienen
Physical Drive physikalisches Gerät (HDD, SDD, PCIe NVME, usw.)
Mirror a standard RAID1 mirror
ZFS software raidz1, raidz2, raidz3 'distributed' parity based RAID
Hot Spare hot spare for ZFS software raid.
Cache a device for level 2 adaptive read cache (ZFS L2ARC)
Log ZFS Intent Log (ZFS ZIL)

ZFS Pools: bestehen aus einem oder mehreren VDEVS, auf einem Pool können ZFS-Dateisysteme erzeugt werden.

ZFS Dataset Types - es gibt drei Typen:

Der folgende Befehl listet die vorhandenen Typen auf:

zfs list -o name,type,mountpoint
NAME       TYPE        MOUNTPOINT
pool1      filesystem  /pool1
pool1/fs1  volume      -
pool1/fs2  filesystem  /pool1/fs2

Einschränkungen / Probleme

  1. Vollbelegung (>90%) macht den Datenspeicher sehr langsam, ab 80% könnte die Geschwindigkeit sinken
  2. import Fehler nach reboots (insbesondere bei mehreren pools): Es sollten immer /dev/disk/by-id/* Aliases benutzt werden!

    /dev/disk/by-id

    Am besten solche die das Modell und die Seriennummer enthalten (Beispiel: nvme-INTEL_SSDPEKNW512G8_BTNH84242VDF511A-part1) oder die SAS-wwn (Beispiel: wwn-0x5000cca04ec097f1-part1). So lassen sich Geräte mit smartctl -i /dev/GERÄT finden.
  3. zfs als root-Dateisystem erfordert einige Anpassungen: https://github.com/zfsonlinux/zfs/wiki/Ubuntu-18.04-Root-on-ZFS
  4. race conditions mit anderen daemons beim mounten aufgrund fehlender systemd.mount integration: https://github.com/zfsonlinux/zfs/issues/4898 https://github.com/zfsonlinux/zfs/pull/7329
  5. Geräte (top-level VDEV) können erst mit Solaris 11.4 entfernt werden https://docs.oracle.com/cd/E37838_01/html/E61017/remove-devices.html
  6. Swap-devices auf zfs-Volumes können Problem bereiten

Arbeitspeicherbelegung begrenzen

ZFS benutzt standardmäßig bis zu 50% des RAMs, die aktuelle Belegung anzeigen:

echo $(( `cat /proc/spl/kmem/slab | tail -n +3 | awk '{ print $3 }' | tr "\n" "+" | sed "s/$/0/"` ))

Beispiel: auf 8G RAM beschränken /etc/modprobe.d/zfs.conf

options zfs zfs_arc_max=8589934592

Zur Laufzeit: echo 8589934592 > /sys/module/zfs/parameters/zfs_arc_max

zfs Distributed RAID (dRAID) vdev type

OpenZFS 2.1.x führt distributed RAID (dRAID) als neuen vdev Typ ein. Dies reduziert bei großen Datenträgerverbünden die Wiederherstellungszeiten.

Administration

Pools

siehe auch: man zpool

pool anlegen

pool aus VDEVs anlegen:

sudo zpool create single-DISK /dev/disk/by-id/DISK1

Redundanz (vergleichbar mit RAID-Level)

pools auflisten

zpool list

pool zerstören

sudo zpool destroy $Poolname

pool Informationen anzeigen

sudo zpool status

Pools erweitern

Datenträger können zu einem pool hinzugefügt werden, jedoch nicht zu einem raidz-Verbund (-f würde ein Raid0 mit der neuen Festplatte erzeugen):

neue disk hinzufügen:

das drunterliegende device (hier 1) erweitern:

rebalance

Die Erweiterung gilt nur für neu geschriebene Daten, vorhandene Daten müssen komplett neu geschrieben werden. Das könnte mit dem PHP-Skript ZFS Balancer erledigt werden.

ZFS Pool Scrubbing

Scrubbing starten (Fortschritt beobachten mit -v):

zpool scrub $Poolname

Scrubbing pausieren:

zpool scrub -p $Poolname

nochmal ausführen für fortsetzen, oder

zpool scrub $Poolname

Diskaustausch

Wenn der scrub Fehler gezeigt hat (zpool status)

zpool detach mypool /dev/BADDISK
zpool attach mypool /dev/GOODDISK /dev/BADDISK  -f

Bzw. ersetzen (resilvering) einer Festplatte:

zpool replace mypool /dev/BADDISK /dev/GOODDISK

Insbesondere falls Geräte mit /dev/sdX aufgenommen wurden, kann es sein das sich Gerätenamen ändern und diese Platten als FAULTED bzw. UNAVAILABLE angezeigt werden. Ein resilver ist leider nicht zu vermeiden aber leider weigert sich zfs diese Platten wieder aufzunehmen (auch mit -f) weil sie Teil des aktiven Pools waren („“). In diesem Fall ist der Export des Pools notwendig (zpool export mypool) und labelclear auf den betroffenen Platten: zpool labelclear /dev/sda

resilvering speed

sysctl vfs.zfs.scrub_delay=0
sysctl vfs.zfs.top_maxinflight=128
sysctl vfs.zfs.resilver_min_time_ms=5000
sysctl vfs.zfs.resilver_delay=0
Einstellung Wirkung
vfs.zfs.scrub_delay „Number of ticks to delay between each I/O during a scrub“
vfs.zfs.resilver_delay „Number of milliseconds of delay inserted between each I/O during a resilver.“
vfs.zfs.top_maxinflight „Maxmimum number of outstanding I/Os per top-level vdev. Limits the depth of the command queue to prevent high latency.“
vfs.zfs.resilver_min_time_ms „spend more time resilvering before it flushes pending transactions.“

iostat-x zeigt mit „w_await“ und „r_await“ langsame disks.

pool umbenennen

…das geht über export/import:

zpool export AlterNAME
zpool import AlterNAME NeuerName

pools importieren

Scan nach pools: zpool import

import eines pools (-f ist nötig wenn der pool vorher an einem anderen Systemen angemeldet war): zpool import $NAME -f

ZFS Intent Logs

ZFS Intent Logs

sudo zpool add meinPool log /dev/DISK1 -f

ZFS Cache Drives

ZFS Cache Drives bieten eine extra caching-Schicht zwischen Arbeitsspeicher und Speichergerät, vor allem für zufällige Lesezugriffe vorrangig statischer Daten.

sudo zpool add meinPool cache /dev/DISK1 -f

ZFS trim

ZFS Dateisysteme

Jeder Pool kann 2^64 ZFS-Dateisysteme enthalten.

erzeugen

Hinweis: Die Größe wird über Quota festgelegt, ohne Angabe wird die Kapazität des pool ausgeschöpft.

Dateisystem anlegen:

zfs create -o acltype=posixacl -o compression=on -o dnodesize=auto -o normalization=formD -o relatime=on -o mountpoint=/media/FS1 meinPool/FS1

Erklärungen:

Verschlüsselung

Dateisystem (verschlüsselt) anlegen (ZoL Version 0.8.x erforderlich) - zusätzliche Parameter:

zfs create -o atime=off -o xattr=sa -o compression=on -o encryption=aes-256-ccm -o keyformat=passphrase -o mountpoint=/media/FS1 meinPool/FS1

datastore öffnen:

zfs load-key meinPool/FS1

datastore schließen:

zfs unload-key meinPool/FS1

Informationen anzeigen:

zfs get -p encryption,keystatus,keyformat,keylocation,encryptionroot

Key ändern (Zugang zum Masterschlüssel der die Daten verschlüsselt):

zfs change-key meinPool/FS1

Falls manueller import erzwungen werden soll: (canmount=off erzwingt manuellen import)

keyfiles

Weitere Informationen:

mounten

Automatische Einhängepunkte:

Auf Anforderung:

Legacy-Einhängepunkte

zfs set mountpoint=legacy meinPool/FS1
ZFS-Property mount Option
atime atime/noatime
devices devices/nodevices
exec exec/noexec
nbmand nbmand/nonbmand
readonly ro/rw
setuid setuid/nosetuid
xattr xattr/noaxttr

Die mount Option nosuid ist ein Alias für nodevices,nosetuid.

löschen

sudo zfs destroy meinPool/FS1

Eigenschaften festlegen

Tuning

Aktuelle Statistiken: arc_summary

https://openzfs.github.io/openzfs-docs/Performance%20and%20Tuning/Workload%20Tuning.html

Deduplication

:!: Deduplication kostet Arbeitsspeicher und hat Auzswirkungen auf die Leistung, siehe ZFS auf Linux/ Deduplizierung und ZFS: To Dedupe or not to Dedupe....

ZFS Snapshots

Vorteile inkrementeller Snapshot gegenüber rsync

  • kein CPU (I/O) overhead weil beide Datenbestände nicht verglichen werden müssen
  • unabhängig vom Dateisystem weil auf Blockebene
  • Daten sind konsistent, wenn rsync ohne snapshot läuft, können Dateien während der Übertragung verändert oder gelöscht worden sein.
zfs auto snapshot

zfsautosnapshot (debian-package)

Snapshot Belegungsberechnung
NAME                  AVAIL USED   USEDSNAP  USEDDS  USEDREFRESERV  USEDCHILD                                                                                                                                                                                                     
meinPool              550G  27,2G        0B     24K             0B      27,2G                                                                                                                                                                                                     
meinPool/FS1          253G  27,1G     3,46G   23,7G             0B         0B                                                                                                                                                                                                     
meinPool/FS1@snap1       -   153K         -       -              -          -                                                                                                                                                                                                     
meinPool/FS1@snap2       -   150K         -       -              -          -
Spalte Bedeutung
NAME Name des Elements
AVAIL freier Speicherplatz
USED Speicherplatz belegt
USEDSNAP Speicherplatz belegt vom Snapshot
USEDDS Speicherplatz belegt vom dataset selbst
USEDREFRESERV belegt von einer ref-reservation
USEDCHILD belegt von einem „children“ des data sets

Links:

ZFS Clones

Ein ZFS clone ist eine schreibbare Kopie eines Snapshots. Der Snapshot kann so lange nicht gelöscht werden wie der Clone besteht.

zfs snapshot -r meinPool/FS1@snapshot1
zfs clone meinPool/FS1@snapshot1 meinPool/FS2

ZFS Send and Receive

Um über Netzwerk zu senden muss die Ausgabe per pipe an ein entferntes System senden:

verschlüsselt Senden: hier muss lt. techgoat wohl -w, –raw angegeben werden damit die Daten exakt so wie in der Quelle verschickt werden (Schlüssel muss nicht geladen werden, testen: funktioniert das entschlüsseln obwohl ?)

ZFS Ditto Blocks

zfs set copies=3 meinPool/FS1

ZFS Volumes

Statt Dateisystemen kann ZFS auch volumes anlegen, das sind Blockgeräte die z.B. in virtualisierten Gästen verwendet werden können.

Aufruf ist wie beim Dateisystem anlegen, nur zusätzlich mit dem Parameter „-V $Größe“:

zfs create -V 2G tank/volumes/v2

Das Volume steht dann unter /dev/tank/volumes/v2 zur Verfügung und kann normal wie blockdevice verwendet werden.

Bei kleiner blocksize kommt es zu ineffizienten Nutzung von Speicherplatz, so dass -b 128k empfehlenswert sein kann.

Volumes vergrößern

Aktuelle Größe anzeigen: zfs get volsize tank/volumes/v2

Vergrößern: zfs set volsize=3GB tank/volumes/v2

Volume Reservierung aufheben

Mit refreservation kann die feste Reservierung des Speicherplatzes aufgehoben ( refreservation=none ) oder auf einen niederigeren Wert als der Maximalwert gesetzt werden.

zfs set refreservation=none tank/volumes/v2

:!: Wenn der Pool vollläuft wird das Dateisystem im Volume korrupt werden.

Monitoring

ZED - ZFS Event Daemon

zpool events

Config: /etc/zfs/zed.d/zed.rc

##
# zed.rc
#
# This file should be owned by root and permissioned 0600.
##

##
# Absolute path to the debug output file.
#
#ZED_DEBUG_LOG="/tmp/zed.debug.log"

##
# Email address of the zpool administrator for receipt of notifications;
#   multiple addresses can be specified if they are delimited by whitespace.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
# Enabled by default; comment to disable.
#
ZED_EMAIL_ADDR="root"

##
# Name or path of executable responsible for sending notifications via email;
#   the mail program must be capable of reading a message body from stdin.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
#
#ZED_EMAIL_PROG="mail"

##
# Command-line options for ZED_EMAIL_PROG.
# The string @ADDRESS@ will be replaced with the recipient email address(es).
# The string @SUBJECT@ will be replaced with the notification subject;
#   this should be protected with quotes to prevent word-splitting.
# Email will only be sent if ZED_EMAIL_ADDR is defined.
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
#
#ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"

##
# Default directory for zed lock files.
#
#ZED_LOCKDIR="/var/lock"

##
# Minimum number of seconds between notifications for a similar event.
#
ZED_NOTIFY_INTERVAL_SECS=3600

##
# Notification verbosity.
#   If set to 0, suppress notification if the pool is healthy.
#   If set to 1, send notification regardless of pool health.
#
#ZED_NOTIFY_VERBOSE=0

##
# Send notifications for 'ereport.fs.zfs.data' events.
# Disabled by default, any non-empty value will enable the feature.
#
#ZED_NOTIFY_DATA=

##
# Pushbullet access token.
# This grants full access to your account -- protect it accordingly!
#   <https://www.pushbullet.com/get-started>
#   <https://www.pushbullet.com/account>
# Disabled by default; uncomment to enable.
#
#ZED_PUSHBULLET_ACCESS_TOKEN=""

##
# Pushbullet channel tag for push notification feeds that can be subscribed to.
#   <https://www.pushbullet.com/my-channel>
# If not defined, push notifications will instead be sent to all devices
#   associated with the account specified by the access token.
# Disabled by default; uncomment to enable.
#
#ZED_PUSHBULLET_CHANNEL_TAG=""

##
# Slack Webhook URL.
# This allows posting to the given channel and includes an access token.
#   <https://api.slack.com/incoming-webhooks>
# Disabled by default; uncomment to enable.
#
#ZED_SLACK_WEBHOOK_URL=""

##
# Pushover token.
# This defines the application from which the notification will be sent.
#   <https://pushover.net/api#registration>
# Disabled by default; uncomment to enable.
# ZED_PUSHOVER_USER, below, must also be configured.
#
#ZED_PUSHOVER_TOKEN=""

##
# Pushover user key.
# This defines which user or group will receive Pushover notifications.
#  <https://pushover.net/api#identifiers>
# Disabled by default; uncomment to enable.
# ZED_PUSHOVER_TOKEN, above, must also be configured.
#ZED_PUSHOVER_USER=""

##
# Default directory for zed state files.
#
#ZED_RUNDIR="/var/run"

##
# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED.  This works for
# device mapper and multipath devices as well.  This works with JBOD enclosures
# and NVMe PCI drives (assuming they're supported by Linux in sysfs).
#
ZED_USE_ENCLOSURE_LEDS=1

##
# Run a scrub after every resilver
# Disabled by default, 1 to enable and 0 to disable.
#ZED_SCRUB_AFTER_RESILVER=0

##
# The syslog priority (e.g., specified as a "facility.level" pair).
#
#ZED_SYSLOG_PRIORITY="daemon.notice"

##
# The syslog tag for marking zed events.
#
#ZED_SYSLOG_TAG="zed"

##
# Which set of event subclasses to log
# By default, events from all subclasses are logged.
# If ZED_SYSLOG_SUBCLASS_INCLUDE is set, only subclasses
# matching the pattern are logged. Use the pipe symbol (|)
# or shell wildcards (*, ?) to match multiple subclasses.
# Otherwise, if ZED_SYSLOG_SUBCLASS_EXCLUDE is set, the
# matching subclasses are excluded from logging.
#ZED_SYSLOG_SUBCLASS_INCLUDE="checksum|scrub_*|vdev.*"
ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event"

##
# Use GUIDs instead of names when logging pool and vdevs
# Disabled by default, 1 to enable and 0 to disable.
#ZED_SYSLOG_DISPLAY_GUIDS=1

Replikation mit inkrementellen snapshots

Beispielskript: inkrementelle Snapshots über Netzwerk

#!/bin/sh
 
# Transfers zfs snapshots to a remote system
# add -v to zfs send if you want transfer-information
 
# set -x
 
# put SSH-user in ssh-config
snapshot_name="backup-latest"
source_reference_snapshot="backup-baseline"
source_server="server1"
source_fs="tank/pool1"
dest_server="backupserver"
dest_fs="tank_backup/pool1_backup"
 
# if you want to run preparations (only once needed!) -> set to "yes" (no backup is made)
first_run=no
 
# usually nothing needs to be changed after this point
source_reference_dataset="$source_fs@$source_reference_snapshot"
source_dataset="$source_fs@$snapshot_name"
dest_dataset="$dest_fs@$snapshot_name"
 
 
# === preparations START ===
if [ first_run == "yes" ]
then
  # create pool (need to edit level and disks here):
  # ssh $dest_server "zpool create $pool_name mirror|raidz|whatever /dev/DISK1 /dev/DISK2"
 
  # and a fs as target:
  ssh $dest_server "zfs create -o acltype=posixacl -o compression=on -o dnodesize=auto -o normalization=formD -o relatime=on $source_fs"
 
  #  the reference-snapshot needs to be created:
  ssh $source_server "zfs snapshot -r $source_reference_dataset"
  # and on the target system, there needs to be a pool...
  exit
fi
# === preparations END ===
 
 
# destroy old snapshots
ssh $source_server "zfs destroy $source_dataset"
ssh $dest_server "zfs destroy $dest_dataset"
 
# make new snapshot
ssh $source_server "zfs snapshot -r $source_dataset"
 
# SSH (encrypted)
# using the agent here (-A), since i need to login on remote host. not needed if source-Host has a access to backup-system via pubkey.
ssh -A $source_server "zfs send -i $source_reference_dataset $source_dataset | ssh $dest_server zfs recv -F $dest_dataset"
 
# netcat (unencrypted, might be faster on slow machines)
#ssh dest_server "nc -w 300 -l -p 2020 | zfs recv -F $dest_dataset" &
#ssh root@source_server  "zfs send -i $source_reference_dataset $source_dataset | nc -w 20 $dest_server 2020"
1)
Momentaufnahmen von Dateisystem