Überblick und Geschichte
ZFS (ursprünglich ‘Zettabyte Filesystem’) ist ein interessantes alternatives Dateisystem. Es wurde ursprünglich von Sun Microsystems ebtwickelt, dann mit OpenSolaris unter einer OpenSource Lizenz freigegeben und letztlich zusammen mit Sun von Oracle gekauft. Wegen dieser Wirren mit nicht zuletzt auch lizenzrechtlichen Unklarheiten, blieb dem System der grosse Erfolg versagt. Apple hatte zumindest Lese-Support schon in OS-X 10.5 eingebaut und wollte, so munkelte man, mittelfristig HFS+ durch ZFS ersetzen. Mit dem Kauf von Sun und der Weiterentwicklung von ZFS unter einer proprietären Lizenz von Oracle wurden diese Pläne aber wieder begraben.
Inzwischen entstand mit OpenZFS ein freier Port, dessen Lizenz eindeutig ist, und der von einer Reihe von Firmen gepusht wird.Man darf die Zukunft von ZFS somit jetzt als gesichert betrachten und sich näher damit befassen.
Installation
- MacOS-X: Download installer von o3x
- Linux: ZFS on Linux (Vorsicht: Nicht “zfs-fuse” installieren, das ist kein “echtes” ZFS, sondern simuliert es quasi auf einem fuse-Dateisystem. Damit ist es wesentlich langsamer und fehleranfälliger, als das echte ZFS.) Spezielle Anweisungen für Ubuntu sind hier, für Arch-Linux hier
Besondere Eigenschaften
Vieles von dem, was für ZFS “erfunden” wurde, fand Einzug in das moderne Linux-Filesystem btrfs. ZFS hat allerdings den Vorteil, stabil und ausgereift zu sein, während viele Teile von btrfs immer noch als Beta oder experimentell gelten. Ausserdem hat ZFS den für mich ausschlaggebenden Vorteil, dass es nicht nur für Linux, sondern z.B. auch für MacOS-X existiert.
Was ist es?
ZFS ist eine Kombination aus LVM (Logical Volume Manager) und Dateisystem: Es kann also physikalische Datenträger verwalten und darauf Dateisysteme organisieren. Bei traditionellen Systemen sind diese Funktionen strikt getrennt (Ein fdisk-Programm erstellt Partitionen, ein RAID-Manager organisiert Schreib- und Lesezugriffe und ein Dateisystem erledigt die “höheren” Funktionen wie Dateinamen und Verzeichnisse). Diese Trennung hat den Nachteil, dass das Dateisystem beispielsweise nichts davon “weiss”, welche Teile des physikalischen Datenträgers überhaupt belegt sind. Das macht Backup- und Restorefunktionen oder das Ersetzen eines RAID-Datenträgers aufwändiger.
Aufbau und Funktionsprinzip
Das Beste an ZFS ist, dass es im Gegensatz zu LVM und btrfs sehr leicht zu verstehen ist. Es gibt eigentlich nur zwei Befehlsgruppen: zpool und zfs. Zpool organisiert Datenpools. Ein solcher Pool kann aus Harddisks oder Partitionen von Harddisks oder sogar Dateien bestehen. Durch einfaches Hinzufügen weiterer Datenträger zu einem bestehenden Pool kann dessen Kapazität erhöht werden, und zwar völlig transparent: Anwendungsprogramme “merken” nichts davon, wieviele Festplatten den Bereich bilden, mit dem sie arbeiten.
In einem solchen Pool kann zfs Dateisysteme erstellen. Das ist optional. Ein root-Dateisystem wird automatisch beim Erzeugen des Pools erstellt. Weitere Dateisysteme entsprechen in etwa den Partitionen traditioneller Dateisysteme. Im Gegensatz zu solchen Partitionen sind ZFS-Dateisysteme aber flexibel: Jede kann beliebig wachsen, so lange, bis entweder eine einzustellende Limite erreicht oder der Pool voll ist. Jedes Dateisystem kann völlig transparent Dinge wie Kompression oder Deduplikation beinhalten.
Der vor allem bei grösseren Systemen wegen seiner Dauer berüchtigte Dateisystem-Check läuft bei ZFS im Hintergrund und ohne, dass man die Partition dafür aushängen muss.
Last but not least sind snapshots unter ZFS sehr einfach zu erstellen. Ein Snapshot ist eine Momentaufnahme des Dateisystems, welches in Sekundenbruchteilen erstellt wird. Einen solchen Snapshot kann man mit “send” auf ein Backupmedium schicken, und zu jedem beliebigen späteren Zeitpunkt dorthin zurückgehen.
Tour d’horizon
Hier ein grundsätzlicher Einstieg (unter MacOSX; für Linux muss man die Devicenamen entsprechend anpassen. Die Namen der Laufwerke
bekommt man unter MacOS mit diskutil list
, unter Linux z.B. mit sudo lsblk
).
sudo zpool create -o ashift=12 zfs1 disk1
Dies erstellt einen pool namens zfs1 aus der Festplatte ‘/dev/disk1’. Wenn man stattdessen nur die zweite Partition der Platte hätte verwenden wollen, hätte man geschrieben:
sudo zpool create -o ahsift=12 zfs1 /dev/disk1s2
Man könnte auch zwei ähnlich grosse Festplatten für einen gespiegelten Pool verwenden:
sudo zpool create -o ashift=12 zfs1 mirror disk2 disk3
Dies im Gegensatz zu:
sudo zpool create -o ashift=12 zfs1 disk2 disk3
In diesem Fall würde zfs einen Pool erstellen, welcher die Grösse von disk2 und disk3 addiert enthält, während das erste Beispiel einen Pool mit der Grösse der kleineren von disk2 und disk3 erstellt, welcher aber durch Spiegelung vor Datenverlust bei Diskausfall gesichert ist.
Man kann die beiden Optionen auch kombinieren:
sudo zpool create -o ashift=12 zfs1 mirror disk2 disk3 mirror disk4 disk5
Hier haben wir einen Pool aus zwei aneinandergehängten Spiegelpaaren erstellt, also insgesamt 4 Disks mit der Kapazität von 2.
Der seltsame Parameter -o ashift=12 dient dazu, dass ZFS eine Sektorgrösse von 4096 Bytes (1«12, daher a’shift’, == 2^12 Bytes) annimmt. Das ist für die meisten aktuellen Festplatten korrekt. Leider melden die meisten Platten aus Kompatibilitätsgründen immer noch 512 Byte ans Betriebssystem, und das ist es dann, was ZFS defaultmässig verwenden würde. Und leider kann man diesen ashift-Parameter nur zum Zeitpunkt der Erstellung des Pools angeben. Wenn man es vergisst, passiert aber nichts wirklich Schlimmes. ZFS braucht dann weniger internen Speicher, arbeitet dafür aber langsamer. Bei heutigen Computern und Datenmengen ist man eher gewillt, mehr Speicher zu spendieren, um Geschwindigkeit zu gewinnen. Daher: Im Zweifel ‘ashift=12’.
Ich glaube, damit ist das Prinzip klar und ich streife nur kurz, dass man statt Spiegeln auch Raids erstellen kann. ZFS erstellt immer eine Variation von Raid-5, die hier raidz heisst. Etwas verwirrenderweise benötigt ein raidz1 3 Disks, von denen eine ausfallen darf, ein raidz2 4 Disks, von denen zwei ausfallen können etc.
Ziemlich ausführliche Infos zu allen möglichen Optionen gibt der Befehl man zpool
, sowohl unter Linux als auch unter Mac.
Nachträgliches Erweitern
Das Ganze wäre natürlich nicht viel wert, wenn man sich beim Einrichten schon ganz sicher sein müsste, welche Harddisk-Konfiguration man für alle Zeiten braucht. Daher kann man jede Konfiguration nachträglich erweitern (aber leider dann nicht mehr ohne Weiteres schrumpfen).
sudo zpool add zfs1 disk6s2
sudo zpool add zfs1 mirror disk6 disk7
erweitert den Zpool um das angegebene Device resp. das angegebene Devicepaar.
sudo zpool attach zfs1 disk6 disk7
macht aus disk6 einen mirror, wenn es noch keiner war. Wenn es schon ein mirror war, macht es einen 3-fach mirror daraus. In jedem Fall werden sofort automatisch alle Daten von disk6 im Hintergrund auf disk7 kopiert (“resilvering”).
Das Ganze kann man noch ergänzen, indem man hot spares und schreib- oder lese-Cache-Devices zu zpools hinzufügt. Beispielsweise kann man schnelle SSDs als Cache-Devices konfigurieren und hat dann so etwas wie Apples FusionDrive.
Filesystem check
Man kann die Korrektheit der Daten checken mit:
sudo zpool scrub zfs1
Das Checken und ggf. Reparieren geschieht online und im Hintergrund. Man kann also normal weiterarbeiten. Fehler sind bei ZFS seltener, als bei anderen Dateisystemen, da wichtige Informationen redundant angelegt werden (auch ohne mirror) und mit Checksummen gesichert sind. Im Fall von Mirror- oder Raidz-Pools werden allfällige trotzdem aufgetretene Fehler jeweils direkt korrigiert.
Das obligate Grrrrrr!
Leider ist ZFS in aktuellen MacOS Versionen nicht mehr richtig integriert. Beim Anstöpseln eines ZFS-Devices meckert der Mac öfters, dass er das Laufwerk nicht lesen kann. Das muss man einfach ignorieren (Bloss nicht “initialisieren”). ZFS bindet das Gerät trotzdem ein. Wenn nicht, muss man mit
sudo zpool import zfs1
nachhelfen.
Und um ein ZFS Device abzuhängen, genügt es auch nicht, es im Finder auszuwerfen. Vielmehr muss man
sudo zpool export zfs1
eingeben.
Bei manchen Betriebssystemen (prominentes Beispiel: Neuere Ubuntu-Versionen mit upstart) ist der Bootprozess parallelisiert, so dass die Reihenfolge, in der Datenträger eingebunden werden, nicht mehr garantiert ist. Was beim vorigen Start /dev/sdc war, könnte beim nächsten Start /dev/sdd werden. Dann findet ZFS möglicherweise nicht mehr die richtigen Datenträger für seine Pools. Um das zu vermeiden, muss man es anweisen, die (unveränderliche) Datenträger-UUID anstelle des Devicenamens zu verwenden. Man macht das entweder beim Erstellen eines Pools mit
sudo zpool create -d /dev/disk/by-id zfs1 sdc
Oder, wenn man den Pool schon ohne diese Option erstellt hat mit
sudo export zfs1
sudo import -d /dev/disk/by-id zfs1
Man muss das nur einmal machen; Zfs merkt es sich für spätere Systemstarts.
Wie auch immer: ZFS ist sowieso nicht als Dateisystem für häufige Datenträgerwechsel gedacht, sondern eher für grosse, permanente Datensammlungen.
Datesysteme / Filesystems
Zpool richtet immer automatisch gleich ein Root-Dateisystem in jedem Pool ein. In unserem obigen Beispiel würde das zfs1 heissen, also genauso wie der pool. Man kann diesem Dateisystem Eigenschaften verpassen, zum Beispiel:
sudo zfs set compression=lz4 zfs1
Eine vollständige Liste aller möglichen Eigenschaften liefert sudo zfs get all
.
Wenn man eine feinere Aufteilung möchte, kann man ene Art Partitionen, nämlich sub-filesystems einrichten.
sudo zfs create -o mountpoint=/Volumes/hans -o quota=5G -o casesensitivity=insensitive zfs1/hans
sudo chown hans /Volumes/hans
sudo zfs create -o mountpoint=/Volumes/lisa -o quota=25G -o compression=off zfs1/lisa
sudo chown Lisa /Volumes/lisa
erstellt zwei Partitionen an entsprechenden mountpoints für Hans und Lisa. Die Partition von Hans kann maximal 5 GB gross werden, die von Lisa 25 GB (Immer vorausgesetzt, dass im Pool zfs1 noch so viel Platz frei ist). Ausserdem wird das von Hans Windows-ähnlich nicht zwischen Gross- und Kleinschreibung unterscheiden, während das von Lisa Unix-typisch case sensitive ist (vererbt von übergeordneten Dateisystem zfs1). Bei Lisa wird dagegen die Datenkompression abgeschaltet, die wir im übergeordneten System zfs1 vorhin eingeschaltet haben, und die zfs1/hans darum geerbt hat.
Quotas können auch user-bezogen oder group-bezogen sein, und Dateisysteme können auch tiefer geschachtelt werden.
Lisa könnte beispielsweise zfs1/lisa/mp3 erstellen, und in diesem Dateisystem die Kompression abgeschaltet lassen, hingegen in zfs1/lisa/documents set compression=on
setzen. ZFS ist da extrem vielseitig.
Snapshots
Alles ist pefekt eingerichtet, und wir wollen uns diesen Zustand des Systems merken.
# Snapshot von zfs1 erstellen, aber nicht von zfs1/hans und zfs1/lisa
sudo zfs snapshot zfs1@ersterSnapshot
# Snapshot von zfs1 und allen darunterliegenden Dateisystemen erstellen
sudo zfs -r snapshot zfs1@ersterSnapshot
# Snapshot von allen Dateisystemen unter zfs1/lisa erstellen
sudo zfs -r snapshot zfs1/lisa@ersterSnapshot
Eine Liste aller Snapshots bekommt man mit
sudo zfs list -t snapshot
Wenn man das System später auf den Zustand eines früheren Snapshots zurücksetzen will, macht man einfach:
sudo zfs rollback zfs1@letzteSicherung
Snapshots betrachten
Noch besser als zfs list
ist folgendes: Im Wurzelverzeichnis
des ZFS Filesystems, also da, wo es gemountet ist, gibt man ein:
cd .zfs
Ja, man kann in dieses Verzeichnis wechseln, obwohl es von ls -la
nicht angezeigt wird. Genauer gesagt: ZFS bindet
es dynamisch ein, sobald man es aufsucht. Darin befindet sich unter Anderem ein Verzeichnis “snapshot”, und darin,
säuberlich sortiert, sind alle Snapshots. Man kann auf diese Weise jede einzelne Datei jedes einzelnen Snapshots
aufsuchen und nötigenfalls herauskopieren. (Ändern kann man nichts, der Snapshot wird read-only gemountet.) Sobald man das
.zfs Verzeichnis wieder verlässt, wird es automatisch abgetrennt.
Snapshot senden
Angenommen, Hans möchte sein komplettes Dateisystem auf den Computer ‘hanspc.neuerArbeitsplatz.org’ umziehen.
sudo zfs send zfs1@hans | ssh hanspc.neuerArbeitsplatz.org zfs recv prstaff@hans
Das kann natürlich einige Zeit dauern, wenn viele Daten zu bewegen sind. ZFS kann nicht zaubern. Wenn man einen entfernten Computer als Backup-Device verwendet, kann man auch inkrementelle Snapshot-Differenzen senden:
sudo zfs send -i zfs1@montag zfs1@dienstag| ssh backup-pc zfsbackups/aktuell
Dies sendet nur die Änderungen des dienstag-snapshots seit dem montag-snapshot.
Auch hier liefert man zfs
mehr Informationen über alle Befehle und deren Optionen.
Deduplikation
Ein gar nicht mal so seltenes Szenario: Man hat einige VirtualMachines oder einige Docker-Container gespeichert. Das sind ziemlich grosse Dateien, die aber dennoch Bereiche haben, in denen sie sich ähneln: Oft wird man dasselbe Betriebssystem und dieselben Standardprogramme in mehreren Containern installiert haben. Wäre es da nicht schön, wenn solche Bereiche nur einmal gespeichert würden?
Hier kommt Deduplikation ins Spiel. Dabei hält ZFS für jeden einzelnen Block im pool einen Hash im Speicher. Wenn es nun den Auftrag erhält, einen neuen Block zu schreiben, prüft es zunächst, ob der Hash dieses Blocks mit einem der vorhandenen Hashs übereinstimmt. Wenn ja, speichert es den Block nicht, sondern nur eine Referenz auf den existierenden Block. Wenn man viele ähnliche Dateien hat, kann man damit ganz erheblich Festplatenspeicher sparen. Allerdings zu einem Preis: Um alle Hashes im Speicher zu halten, ist entsprechend viel RAM nötig. Als Faustregel sollte man pro Terabyte Plattenkapazität 1 bis 1.5 GB RAM haben. Und um nachzuschauen, ob ein Block schon existiert, muss beim Schreiben jeder einzelne Blockhash mit jedem bereits existierenden Hash verglichen werden. Es ist nicht schwer, sich vorzustellen, dass dies einiges an Prozessorzeit kostet. Dazu kommen Sicherheitsüberlegungen: Wenn ein Block, der in zehn VMs benötigt wird, wegen eines Festplattenfehlers ausfällt, dann sind zehn VMs kaputt und nicht nur eine, wie es ohne Deduplikation der Fall wäre.
Leider benutzt Deduplikation auch immer den ganzen Pool. Wenn man es nur für ein Filesystem des Pools aktiviert, dann werden zwar nur die Dateien dieses Filesystems dedupliziert, aber es werden dennoch Hashes sämtlicher Blöcke des gesamten Pools erstellt und verwaltet.
Also zusammengefasst: Ein cooles Feature, das man aber nur einschalten sollte, wenn man wirklich viele “ähnliche” Dateien hat, und wenn der Computer genug RAM und einen ausreichend schnellen Prozessor hat. Die Entscheidung, wann das wirklich sinnvoll ist, ist schwierig zu treffen und wird durchaus auch kontrovers diskutiert. In den meisten Fällen sollte man Deduplikation wohl eher deaktiviert lassen (was auch das Standardverhalten von ZFS ist). Insbesondere, weil Festplattenpreise schneller fallen, als RAM-Kosten, und weil es oft einfacher ist, mehr Harddisks anzuschliessen, als den Speicher zu erweitern. Eine recht ausführliche Behandlung des Themas ist hier zu finden.
Freigabe übers Netzwerk
Wenn man mit Windows- und Mac Computern auf ein ZFS Dateisystem zugreifen möchte, genügt folgendes:
sudo set sharesmb=on zfs1
Das ist alles. Sofort wird ‘zfs1’ übers Netz freigegeben. Auch hier kann man selbstverständlich den Parameter für darunterliegende Dateisysteme unterschiedlich definieren:
sudo set sharesmb=off zfs1/lisa
Wenn man nicht (nur) mit dem SMB-Protokoll freigeben möchte, sondern (auch) mit dem (in Unix gebräuchlicheren) NFS-Protokoll, dann kann man
sudo set sharenfs=on zfs1
angeben.
Herausfinden, welche physikalischen Laufwerke zu einem zpool gehören
Zumindest mir geht es manchmal so, dass ich nach einiger Zeit nicht mehr weiss, welche physischen Disks ich welchem zpool zugeordnet hatte.
zpool status -v
hilft leider nur bedingt, da hier zwar die Disks angezeigt werden, aber mit einem Namen, den man zum Beispiel mit
lsblk -o name,uuid,partuuid,ptuuid
nicht findet.
Abhilfe bietet folgender Befehl:
udevadm info --query=property --name=/dev/sdX | grep WWN
wobei man für X nacheinander alle Festplatten einsetzt. Damit erhält man den WWN (World Wide Name) der jeweiligen Platte, und das ist der, den zpool anzeigt.
Schluss und weiterführende Literatur
ZFS wurde für sehr grosse Dateisysteme entwickelt. Daher auch der ursprüngliche Name “Zettabyte File System”. Ein Zettabyte sind eine Milliarde Terabytes. Eine schnelle Festplatte, die 200MB/s schreiben kann, braucht 5 Sekunden, um ein GB vollzuschreiben und 5000 Sekunden (=etwas weniger als eineinhalb Stunden) für ein Terabyte. Eine solche Platte bräuchte mehr als 158000 Jahre, um ein Zettabyte zu füllen. ZFS kann mit Systemgrössen bis 256 Billionen Zettabytes umgehen, und jedes Verzeichnis kann bis zu 256 Billiarden Einträge enthalten.
Somit scheint der Anspruch der ZFS-Entwickler gerechtfertigt, ein Dateisystem gebaut zu haben, das “für immer” genügt. Natürlich hat diese Auslegung auf gigantische Datenmengen auch Nachteile. Zum Beispiel verwendet ZFS durchgehend 128 Bit Pointer, was für heutige (64 Bit) Prozessoren nicht die optimale Datengrösse ist. Dies führt einerseits zu erhöhtem Platzbedarf für Verwaltungsstrukturen und andererseits auch zu Geschwindigkeitsnachteilen. ZFS braucht relativ viel Speicher und einen einigermassen modernen Prozessor. (Da ZFS aber auch in einigen NAS Geräten eingesetzt wird, scheint der Anspruch an die Hardware doch auch nicht unerträglich hoch zu sein. Limitierend ist ohnehin die Schreibgeschwindigkeit auf die Platte selbst, nicht die Rechenarbeit des Dateisystems)
Die Auslegung von ZFS für grosse Systeme führt auch dazu, dass es eher in der Domäne der Systemadministratoren, als der Hobbyisten und Privatnutzer ist. Recherchen in Newsgroups sind darum für ZFS Einsteiger oft nicht sehr ergiebig. Oft findet man nur die Fragen, auf die niemand geantwortet hat, oder Antworten des Typs “wenn du das fragen musst, ist zfs sowieso nichts für dich”.
Aber wie ich oben gezeigt habe, hat ZFS durchaus auch Eigenschaften, die für kleinere, privat betreute Netzwerke sinnvoll sein können. Und manchmal hat man ja auch einfach Lust, mal etwas Neues auszuprobieren, und es geht auch nicht immer im absolut lebenswichtige oder systemkritische Datenbestände.
Eine erste Quelle für Informationen sind wie gesagt die beiden Kommandos man zfs
und man zpool
. Sehr viel Information
gibt es auf der OpenZFS und der OpenZFS on X
Website, allerdings in einer Struktur, die es dem Einsteiger schwer macht, Antworten zu finden.
Sehr gut strukturiert und ausführlich, ausserdem mit vielen Beispielen anschaulich gemacht, ist Oracles ZFS-Manual Hier geht es allerdings um das proprietäre Oracle ZFS und nicht um OpenZFS. Aber die Unterschiede sind derzeit noch klein genug, dass das Handbuch auch für OpenZFS geeignet ist.
Eine gute Zusammenfassung finde ich auch diesen Artikel: https://blog.wyraz.de/linux/das-optimale-zfs-dateisystem-teil-1-erzeugen-eines-pools-mit-optionaler-ssd-beschleunigung/