ZFS ist out-of-the-box ein guter Generalist. Das heißt: für jeden Workload ordentlich, für keinen optimal. Wer einen Pool für eine konkrete Anwendung baut — VM-Storage, Backup-Target, File-Server, Datenbank — kann mit ein paar wenigen Dataset-Properties spürbar mehr Performance, weniger Speicherverbrauch und längere SSD-Lebensdauer erreichen.
Dieser Artikel zeigt die wichtigsten Stellschrauben in der richtigen Reihenfolge. Keine erfundenen Benchmarks — wo es Tradeoffs gibt, beschreiben wir sie qualitativ. Eigene Tests im Lab oder in einem Staging-Pool sind durch nichts zu ersetzen.
Was beim Pool-Setup nicht mehr änderbar ist
Bevor wir zu tunbaren Properties kommen, eine Erinnerung an die unwiderruflichen Entscheidungen beim Pool-Create:
ashift— sector-size-alignment, gesetzt beim VDEV-Create. Empfehlung:ashift=12(4K-Sectors) für moderne SSDs und Enterprise-HDDs. Bei NVMe und manchen Enterprise-SSDs istashift=13(8K) sinnvoll. Falscher ashift = Write-Amplification, nicht nachträglich änderbar.- VDEV-Topologie — Mirror, RAIDZ1/2/3, dRAID. Eine RAIDZ-Konfiguration lässt sich nicht in einen Mirror umwandeln. RAIDZ-Expansion (ab OpenZFS 2.3) erweitert nur, ändert nicht die Topologie. Siehe ZFS RAID-Level erklärt.
- Encryption-Properties auf Pool-Ebene — nachträglich nicht änderbar.
Wer hier falsch dimensioniert, kann später nichts mehr durch Properties retten. Der Rest dieses Artikels behandelt das, was sich online und ohne Datenverlust ändern lässt.
recordsize — die wichtigste Stellschraube
recordsize ist die maximale logische Blockgröße, mit der ZFS Daten in ein Dataset schreibt. Default: 128K. Das ist für File-Server mit gemischten Dateigrößen okay, für VMs oder Datenbanken aber meist suboptimal.
Faustregel: recordsize sollte zur typischen IO-Größe des Workloads passen.
| Workload | Empfehlung recordsize | Begründung |
|---|---|---|
| File-Server (gemischte Dateien) | 128K (default) | Generalist, gute Balance |
| Große Mediendateien (Video, Backups, Images) | 1M | Weniger Metadaten-Overhead, höhere Streaming-Performance |
| VM-Images (Proxmox, qcow2, raw) | 64K oder 128K | Anwendungs-IO-Größe meist 4–16K, aber Multi-Block-Operationen profitieren |
| Datenbanken (PostgreSQL, MySQL InnoDB) | 16K | Datenbank-Page-Size matchen — typisch 8K (Postgres) oder 16K (InnoDB) |
| Microsoft SQL Server (Datenfiles) | 64K | SQL Server schreibt in 64K-Extents |
| Backup-Targets (Veeam, PBS-Chunks, Restic) | 1M | Lange sequenzielle Writes, dedup-orientierte Speicherung |
Wichtig: recordsize gilt ab dem Setzen für neu geschriebene Blöcke. Bestehende Daten behalten ihre alte Blockgröße bis zum nächsten Rewrite. Wer ein Dataset umstellt, sollte die Daten neu kopieren (zfs send | zfs receive in ein neues Dataset) oder einfach abwarten, bis sich die Dataset-Inhalte durch normale Schreibvorgänge erneuert haben.
# recordsize für ein VM-Dataset
zfs set recordsize=64K tank/vms
# recordsize für ein Datenbank-Dataset (Postgres)
zfs set recordsize=16K tank/postgres
# recordsize für ein Backup-Target
zfs set recordsize=1M tank/backups
atime=off — leiser Killer entfernt
atime (Access Time) ist die Property, die bei jedem Read den Lesezeitstempel der Datei aktualisiert — also einen Write pro Read. Das war in 1990er-Unix-Workloads sinnvoll. Heute ist es fast immer schädlicher Overhead:
- Für jeden Read fällt ein Metadaten-Write an
- SSDs werden unnötig belastet (Write-Amplification)
- File-Server, Backup-Targets, VM-Storage profitieren nicht von atime
zfs set atime=off tank
Auf Pool-Root setzen, vererbt sich auf alle Datasets. Ausnahme: Wenn Anwendungen wirklich auf atime angewiesen sind (Mail-Server in einigen Konfigurationen, manche Quota-Tools). In dem Fall selektiv auf atime=off auf den Datasets verzichten, die diese Anwendungen halten.
Modernere Alternative: relatime=on aktualisiert atime nur, wenn die letzte Update-Zeit älter als 24h oder vor der mtime/ctime liegt. Reduziert die meisten unnötigen Writes, ohne atime völlig zu verlieren.
# Wenn atime wirklich gebraucht wird, aber Schonung gewünscht
zfs set atime=on tank/mailserver
zfs set relatime=on tank/mailserver
Komprimierung — lz4, zstd-3, zstd-19
Komprimierung ist in fast allen Szenarien ein klarer Gewinn — weniger Platzverbrauch und oft sogar schnellere IO, weil weniger Daten von/zur Disk fließen müssen. Die Frage ist nur: welcher Algorithmus.
| Algorithmus | CPU-Last | Komprimierungsrate (typisch) | Latency | Anwendungsfall |
|---|---|---|---|---|
lz4 | Sehr niedrig | 1,2:1 – 2,0:1 | Sehr niedrig | Default für VMs, Datenbanken, alles latency-sensitiv |
zstd-3 | Niedrig–mittel | 1,5:1 – 2,5:1 | Niedrig | Generalist mit besserer Rate als lz4, kaum CPU-Mehrkosten auf modernen EPYC/Xeon |
zstd-9 | Mittel–hoch | 1,8:1 – 3,0:1 | Spürbar höher | File-Server mit überwiegend Read-Workload |
zstd-19 | Sehr hoch | 2,0:1 – 4,0:1 | Hoch | Archiv- und Cold-Storage, wenn Schreiben selten und CPU verfügbar |
gzip-6 | Hoch | ähnlich zstd-9 | Hoch | Legacy — heute selten Vorteil gegenüber zstd |
off | Keine | 1,0:1 | Niedrigste | Nur bei bereits komprimierten Daten (z.B. Veeam-Repository mit eigener Komprimierung) |
Tradeoffs in der Praxis:
- VMs und Datenbanken:
zstd-3ist oft die bessere Wahl alslz4— kaum messbare Latency-Erhöhung auf modernen CPUs, deutlich bessere Komprimierung. - All-Flash-Pools mit hoher IO-Last:
lz4bleibt sicher; zstd nur nach Lab-Test. - Backup-Targets: Wenn die Daten bereits dedupliziert + komprimiert ankommen (PBS, Veeam Hardened Repo):
compression=offoder maximallz4. Mehr bringt nichts und kostet CPU. - Cold-Storage / Archive:
zstd-19lohnt sich. Geschrieben wird selten, gelesen wird selten, jeder Prozent gesparter Platz zählt.
# Default für meiste Datasets
zfs set compression=zstd-3 tank
# All-Flash-VM-Pool mit Latency-Priorität
zfs set compression=lz4 tank/vms
# Archive
zfs set compression=zstd-19 tank/archive
# Backup-Target mit eingehend bereits komprimierten Daten
zfs set compression=off tank/veeam
Wer den Effekt prüfen will: zfs get compressratio dataset zeigt die tatsächlich erreichte Rate auf vorhandenen Daten.
Mehr dazu im Detail unter ZFS-Komprimierung in der Praxis.
special_small_blocks — Metadaten und kleine Files auf NVMe
Wenn der Pool ein Special VDEV (separates Mirror-VDEV aus NVMe) hat, kann special_small_blocks dafür sorgen, dass nicht nur Metadaten, sondern auch kleine Datenblöcke dort landen. Das beschleunigt File-Server-Workloads mit vielen kleinen Files dramatisch — die Hot-Files liegen auf NVMe, nur große Files auf den langsameren HDDs.
# Special-VDEV muss bereits angehängt sein (zpool add tank special mirror ...)
zfs set special_small_blocks=64K tank/fileserver
Werte zwischen 32K und 128K sind in der Praxis sinnvoll. Wichtig: Das Special-VDEV muss redundant ausgelegt sein (mindestens Mirror) — fällt es aus, ist der gesamte Pool tot. Mehr im Proxmox-ZFS-Tuning-Artikel.
primarycache / secondarycache
Diese beiden Properties steuern, was im ARC (RAM) und L2ARC (NVMe-Cache) gehalten wird:
| Wert | Bedeutung |
|---|---|
all (default) | Daten + Metadaten cachen |
metadata | Nur Metadaten cachen |
none | Nichts cachen |
Sinnvolle Anwendungen:
- Sequenzielle Backup-Reads:
primarycache=metadata— Backup-Daten werden einmal gelesen, kein Wert im ARC. RAM bleibt für andere Datasets frei. - Datenbanken mit eigenem Cache (z.B. PostgreSQL shared_buffers):
primarycache=metadata— die DB cached selbst effektiver, ARC nur für Metadaten. - Hot-Read-Workloads (File-Server-Profile):
primarycache=allbelassen.
# Backup-Dataset: ARC nur für Metadaten
zfs set primarycache=metadata tank/backups
zfs set secondarycache=metadata tank/backups
sync — vorsichtig nutzen
sync steuert, wie ZFS mit synchronen Schreibvorgängen umgeht:
standard(default): Schreibvorgang wartet auf SLOG/ZIL-Bestätigung — sicher, konsistentalways: Erzwingt sync auch für asynchrone Writes — sehr sicher, sehr langsamdisabled: Ignoriert sync-Anforderungen — schnellster Write, aber Daten der letzten Sekunden gehen bei Stromausfall verloren
sync=disabled ist eine Falle. Es ist verlockend für Benchmark-Werte, aber riskant in produktiven Setups:
- Sicher für: temporäre Scratch-Datasets, Build-Artefakte, Caches, die jederzeit neu erzeugt werden können
- Riskant für: Datenbanken, VM-Images, alles, was Konsistenz braucht
# Nur für nachweislich unkritische Scratch-Daten
zfs set sync=disabled tank/scratch
Wer sync-Performance braucht, sollte stattdessen ein dediziertes SLOG-Device (Intel Optane, hochwertige NVMe mit Power-Loss-Protection) hinzufügen — das beschleunigt sync ohne Konsistenzverlust.
logbias — throughput vs. latency
logbias=throughput ändert das Verhalten des SLOG: sync-Writes gehen direkt in den Pool statt über das SLOG. Macht für datenbankartige Workloads mit sehr großen sync-Writes Sinn, wo das SLOG sonst zum Engpass würde.
zfs set logbias=throughput tank/large-db
Default logbias=latency ist für die meisten Anwendungen richtig.
redundant_metadata
redundant_metadata=most reduziert die Anzahl der Metadaten-Kopien von 2 auf 1 für die meisten Blöcke (kritische Metadaten bleiben doppelt). Spart Platz, reduziert aber die Wiederherstellbarkeit bei korrupten Metadaten-Blöcken. Selten zu empfehlen, außer bei wirklich knappem Speicher in sicheren Umgebungen.
Einmal-Setup-Checkliste für neue Pools
Ein pragmatischer Default-Setup-Block für einen frischen Pool:
# Pool-weit
zfs set atime=off tank
zfs set compression=zstd-3 tank
zfs set xattr=sa tank # Erweiterte Attribute inline, weniger Overhead
zfs set acltype=posixacl tank # Falls POSIX-ACLs gebraucht werden
# VM-Dataset
zfs create -o recordsize=64K -o compression=lz4 tank/vms
# Datenbank-Dataset
zfs create -o recordsize=16K -o compression=lz4 -o logbias=latency tank/postgres
# Backup-Target
zfs create -o recordsize=1M -o compression=off -o primarycache=metadata tank/backups
# Generelles File-Dataset
zfs create -o recordsize=128K tank/files
Das sind keine universellen Wahrheiten, sondern erfahrungsbasierte Startwerte — bei produktivem Einsatz mit echten Workloads validieren und nachjustieren.
Was die Tuning-Wirkung nicht ersetzt
Properties tunen, was vorhanden ist. Sie reparieren nicht:
- Zu wenig RAM für ARC. Faustregel: 1 GB RAM pro 1 TB Pool, mehr bei dedup oder vielen kleinen Files. Wer hier knausert, sieht das in jedem Workload.
- Falsche VDEV-Topologie. Ein einzelnes RAIDZ2 aus 12 großen HDDs für VM-Workload wird auch mit perfektem Tuning enttäuschen — VMs brauchen Mirror-VDEVs oder All-Flash.
- Fragmentierten Pool > 80% Belegung. ZFS verlangsamt sich ab ca. 80% Fülle deutlich. Mehr Platz lassen oder vergrößern.
- Falscher Storage-Stack. Spinning-HDDs für High-IOPS-Workloads bleiben auch mit perfektem Tuning langsam.
DATAZONE-Empfehlung
Tuning ist kein Selbstzweck — es ist die letzte Schicht über sauber dimensionierter Hardware und richtiger Pool-Topologie. Reihenfolge:
- Hardware passend zur Anwendung (TrueNAS-Modellwahl oder Proxmox-Architektur-Planung)
- VDEV-Topologie richtig beim Pool-Create (ZFS RAID-Level)
- Default-Properties (atime=off, compression=zstd-3, xattr=sa)
- Workload-spezifische Datasets (recordsize, compression, sync, primarycache pro Dataset)
- Messen.
zpool iostat,arcstat, Anwendungs-Metriken (siehe Grafana-Stack, TrueNAS-SMART-Monitoring)
Wir helfen bei der Pool-Auslegung und beim Tuning bestehender Setups. Erfahrungsgemäß lassen sich bei ungetunten KMU-Pools 20–50 % Performance ohne neue Hardware herausholen — wenn die Dimensionierung grundsätzlich stimmt.
Quellen und weiterführende Artikel
Mehr zu diesen Themen:
Weitere Artikel
Cloud-Backup-Kosten 2026: B2 vs. Wasabi vs. Storj Update
Update zum bestehenden Vergleich der Cloud-Backup-Anbieter. Was hat sich seit Mai 2026 geändert? Preise, Egress-Modelle, Minimum-Storage-Perioden und Rechenbeispiele für 1, 10 und 100 TB pro Monat — inklusive Hetzner Storage Box und AWS S3 Glacier Deep Archive.
TrueNAS HA: Wann lohnt sich der Dual-Controller?
Hochverfügbarkeit per Dual-Controller ist bei TrueNAS nicht trivial — weder im Preis noch im Konzept. Wann sich HA wirklich lohnt, was es nicht löst und wann zwei Single-Controller-Systeme die bessere Wahl sind.
TrueNAS Snapshot-Strategien für VM-Storage
Spezifisch für VM-Storage: VM-konsistente vs. Crash-consistent Snapshots, TrueNAS- vs. Hypervisor-Snapshots, Dataset-Layout pro VM oder pro Pool, VM-aware Backup, Restore-Pfade, Retention-Trade-offs.