Dateisystem-Wahl für KI-Server: XFS, ZFS, ext4 – und warum Btrfs nicht auf der Liste steht

Wenn Sie gerade 40k € für GPUs ausgegeben haben, verdient das Dateisystem, auf das Sie Ihre Daten kippen, mehr als fünf Minuten Nachdenken. Der Ubuntu-Installer legt bereitwillig überall ext4 an; für viele KI-Workloads ist das die richtige Antwort, für manche nicht. Wählen Sie für ein 50-TB-Datenvolumen das falsche Dateisystem, verlieren Sie Durchsatz, verlieren Sie Daten oder sehen zu, wie Ihr DataLoader hinter einem Metadaten-Engpass Däumchen dreht.

Hier geht es darum, welches Dateisystem auf einem KI-Server der Kentino-Klasse (4–8 GPUs, NVMe-Boot, NVMe-Scratch, langsamere Bulk-Ebene) wohin gehört. Ubuntu 22.04 / 24.04, Kernel 6.x.

Die Kurzfassung

Einhängepunkt Workload Dateisystem Warum
/ (Boot, Root) Betriebssystem, Pakete, Logs ext4 langweilig, bewährt, wiederherstellbar
/scratch (NVMe RAID0) aktive Trainings-Shards, flüchtige Schreibvorgänge XFS Durchsatz, paralleler Verzeichnis-I/O
/data (RAID10) Trainingsdatensätze, Modell-Checkpoints XFS oder ZFS XFS für rohe Geschwindigkeit; ZFS, wenn Sie Snapshots und Prüfsummen wollen
/archive (RAID-Z2/6) abgeschlossene Läufe, Kaltspeicher für Datensätze ZFS Kompression, Prüfsummen, Snapshots
/home Benutzerverzeichnisse, Notebooks ext4 kleine Dateien, wenig Konkurrenz

In einem Absatz: ext4 für das Betriebssystem, XFS für heißen Scratch-Speicher, ZFS dort, wo Integrität wichtiger ist als die letzten 10 % Durchsatz, kein Btrfs in der Produktion.

ext4 – die langweilige Voreinstellung, die meistens richtig ist

ext4 ist seit über einem Jahrzehnt Standard unter Ubuntu, Debian, Fedora und RHEL. Gut verstanden, mit fsckwiederherstellbar, 16 TB pro Datei, 1 EB pro Volume. Nichts Aufregendes – genau das ist der Punkt.

Nutzen Sie ext4 für das Root-Dateisystem (jeder Ubuntu-Live-USB-Stick weiß, wie man es repariert; weit weniger wissen, wie man einen zpool importiert), für /homeund für VM-Image-Speicher in kleinem bis mittlerem Maßstab.

Wo ext4 aufhört, die richtige Wahl zu sein: breit paralleler I/O (das Journal serialisiert Metadaten-Updates – zwanzig DataLoader-Worker auf einem ext4-Volume laufen längst ins Journal-Limit, bevor die NVMe ausgelastet ist); einzelne riesige Dateien (funktioniert, aber die Extent-Zuweisung ist bei sequenziellen Dateien > 100 GB weniger geschickt als bei XFS – Trainings-Shards, Checkpoints, Videokorpora); Snapshots (nativ keine; LVM-Thin-Snapshots funktionieren, sind aber umständlich).

mkfs.ext4 -L root /dev/nvme0n1p2

Wenn Sie sich bei einem KI-Workload beim exotischen ext4-Tuning wiederfinden, haben Sie das falsche Dateisystem gewählt.

XFS – die richtige Wahl für heißen Scratch-Speicher und Trainingsdaten

XFS war ein SGI-Dateisystem für sequenziellen I/O mit hohem Durchsatz auf großen Arrays. Dieses Erbe passt fast perfekt zu KI-Workloads: große Dateien (Trainings-Shards, Parquet, WebDataset-Tars, Checkpoints), sequenzielle Lesezugriffe, viele parallele Leser und die Gelassenheit, dass sich die Daten notfalls neu erzeugen lassen.

Was XFS kann und ext4 nicht: Allocation Groups – das Volume zerfällt in 4–32 unabhängige Gruppen, die ohne globalen Journal-Lock parallel lesen und schreiben, also genau das, was ein DataLoader mit vielen Workern braucht; verzögerte und spekulative Vorabzuweisung damit große sequenzielle Schreibvorgänge zusammenhängende Extents bekommen; praktisch keine Dateigrößenbegrenzung (8 EB); und xfs_growfs für die zuverlässige Erweiterung per Einzeiler nach einem RAID-Ausbau.

Was es nicht kann: keine nativen Snapshots, keine Prüfsummen auf Dateidaten (Metadaten sind seit 2014 per CRC geschützt), kein Verkleinern – nur Vergrößern.

Ein sinnvolles mkfs.xfs für ein Scratch-Volume aus 8× NVMe im RAID0 mit 64 KiB Chunk-Größe:

# su = Stripe Unit = Chunk-Größe; sw = Anzahl der Datenträger
mkfs.xfs -f -d su=64k,sw=8 -l size=512m -L scratch /dev/md0

# largeio + swalloc: sinnvolles Verhalten bei I/O >1 MB
# allocsize=1g: aggressive Vorabzuweisung für große sequenzielle Schreibvorgänge
# noatime: spart einen Schreibvorgang je Lesezugriff bei hoher DataLoader-Last
mount -o noatime,largeio,swalloc,allocsize=1g /dev/md0 /scratch

noatime und largeio sind dabei am wichtigsten. Bei kleinen Dateien ist XFS brauchbar, aber das ist nicht seine Stärke – bei Hunderten Millionen Bildern <16 KB packen Sie besser in WebDataset / Parquet / LMDB um, statt das Dateisystem zu wechseln (siehe unten).

ZFS – die richtige Wahl, wenn Integrität, Snapshots oder Kompression zählen

ZFS ist Dateisystem, Volume-Manager und Software-RAID in einem:

  • Durchgängige Prüfsummen. Bit-Rot wird beim Lesen erkannt und bei vorhandener Redundanz unbemerkt korrigiert. Für einen 50-TB-Datensatz, der zwei Jahre auf Magnetplatten liegt, zählt das; für flüchtigen NVMe-Scratch über sechs Wochen nicht.
  • Snapshots und Clones. Atomar, Copy-on-Write, praktisch kostenlos. Vor einem Lauf einen Snapshot ziehen, einen Clone abzweigen, zurückrollen – genau für diesen Workflow gibt es ZFS.
  • Integrierte Kompression. lz4 ist standardmäßig aktiv; zstd liefert bessere Kompressionsraten. Bei Text, JSON und Parquet erhöht Kompression den effektiven Durchsatz meist sogar, weil die CPU-Kosten geringer sind als der eingesparte I/O.
  • ARC – ein eigener RAM-basierter Lesecache, getrennt vom Linux-Page-Cache. Die berüchtigte Fußangel.
  • Natives RAID-Z – kein mdadm nötig.

Was ZFS für KI nicht gut kann: frisst RAM (der ARC nimmt sich standardmäßig rund 50 % des Systemspeichers – auf einem Server mit 512 GB sind das 256 GB, die dem Kernel plötzlich fehlen, und Trainingsjobs, die mit Page-Cache oder Huge Pages rechnen, werden vom OOM-Killer beendet; begrenzen Sie den ARC); nicht das Schnellste bei rein sequenziellen Lesezugriffen (gut abgestimmtes XFS auf NVMe-RAID0 liegt 15–30 % vor ZFS – Prüfsummen und Copy-on-Write kosten echte Rechenzeit); ignoriert O_DIRECT (sämtlicher I/O läuft konstruktionsbedingt über den ARC – für die meisten Workloads unproblematisch, aber unvereinbar mit GPUDirect Storage).

ARC-Tuning – der eine Regler, den Sie setzen müssen

Auf einer frischen Ubuntu-Installation mit ZFS auf einer Maschine mit 512 GB beansprucht ZFS 256 GB für den ARC. Setzen Sie zfs_arc_max bei der Installation, nicht nach dem ersten OOM.

# ARC auf 64 GB begrenzen. Angabe in Bytes, nicht GB. 64 * 1024^3 = 68719476736
echo "options zfs zfs_arc_max=68719476736" | sudo tee /etc/modprobe.d/zfs.conf
echo 68719476736 | sudo tee /sys/module/zfs/parameters/zfs_arc_max   # sofort anwenden
sudo update-initramfs -u                                             # dauerhaft

Faustregel: Begrenzen Sie den ARC auf 10–20 % des Systemspeichers auf einem KI-Server. Die klassische Dimensionierung „2 GiB Basis + 1 GiB je TiB“ stammt aus dem Storage-Umfeld; auf einer KI-Maschine ist der Großteil des RAM für Modellgewichte, Aktivierungen und den Page-Cache des Frameworks reserviert.

Ein vernünftiges ZFS-Layout für die Datenebene eines KI-Servers

# 8 × 16 TB SAS in zwei RAID-Z2-vdevs (je 6+2) — zwei vdevs bringen 2× IOPS
zpool create -o ashift=12 \
  -O compression=zstd -O atime=off -O xattr=sa -O recordsize=1M \
  data \
  raidz2 /dev/sd[a-h] \
  raidz2 /dev/sd[i-p]

# Datasets passend zum jeweiligen Workload dimensioniert
zfs create -o recordsize=1M   data/datasets       # große Trainings-Shards
zfs create -o recordsize=128k data/checkpoints    # gemischte Größen
zfs create -o recordsize=16k  data/metadata       # kleine Dateien (json, yaml)

zfs snapshot data/datasets@pre-run-2026-05-14
zfs rollback data/datasets@pre-run-2026-05-14

ashift=12 = 4-KiB-Blöcke – wenn Sie das beim Anlegen des Pools falsch setzen, lässt es sich nur durch Zerstören des Pools korrigieren. recordsize=1M für Workloads mit großen Dateien (die Voreinstellung von 128 KiB ist für Shards im Gigabyte-Bereich zu klein). xattr=sa speichert erweiterte Attribute inline, was massiv schneller ist als die Voreinstellung.

Btrfs – für produktive KI-Systeme grundsätzlich meiden

Btrfs bietet konzeptionell denselben Funktionsumfang wie ZFS – Copy-on-Write, Snapshots, Prüfsummen, integriertes RAID. Auf dem Papier passt das; in der Praxis empfehlen wir es auf Kentino-Servern nicht. RAID5/6 hat bekannte Fehler mit Datenverlust, die das Projekt selbst als nicht produktionsreif kennzeichnet (RAID1/10 sind stabil, die Paritätsmodi nicht); die Performance bricht unter dem Fragmentierungsmuster ein, das KI-Workloads erzeugen (Gradient-Checkpoints, Caches); die Snapshot-Performance fällt oberhalb einiger hundert Snapshots steil ab, was ein Workflow mit einem Snapshot je Experiment binnen eines Quartals erreicht; und das Tooling für Replikation, Monitoring und Scrub-Planung ist weniger ausgereift als bei ZFS oder XFS. Auf einem Laptop völlig in Ordnung. Für einen Multi-GPU-Server mit zweistelligen Terabyte-Mengen an Trainingsdaten nehmen Sie XFS oder ZFS.

RAID-Layouts – womit Sie das Dateisystem kombinieren

RAID-Level Einsatzfall Redundanz Anmerkungen
RAID0 Scratch (flüchtig, neu erzeugbar) keine nur für Daten, die Sie wiederherstellen können
RAID10 Trainingsdatensätze, Checkpoints 1 je Spiegel beste Kombination aus Tempo und Sicherheit für heiße Daten
RAID-Z1 / RAID5 bei Neuaufbauten meiden 1 Festplatte Rebuild-Zeiten bei Laufwerken ab 16 TB machen Z1 riskant
RAID-Z2 / RAID6 Archiv, Kaltspeicher für Datensätze 2 Festplatten die richtige Wahl für Massendaten
RAID-Z3 breite Arrays (ab 12 Festplatten) 3 Festplatten nur, wenn die Breite des Arrays es erzwingt

Bei Laufwerken ab 16 TB kann der Rebuild einer einzelnen Platte 24–72 Stunden dauern, und ein zweiter Ausfall unter Laufwerken derselben Fertigungscharge ist in diesem Zeitfenster nicht vernachlässigbar. Einfache Parität ist nicht länger die sichere Voreinstellung. Nehmen Sie Z2/RAID6 oder Spiegel.

Kleine Dateien gegen große Dateien

Die Frage, über die mehr Leute stolpern als über die Wahl des Dateisystems: Wie verhält sich Ihr Dateisystem bei 50 Millionen 4-KB-Bildern in einem Verzeichnisbaum? Die Antwort lautet für jedes hier genannte Dateisystem: schlecht.

Metadaten je Datei (Inode, Dentry, Zeitstempel, erweiterte Attribute) belegen 200–500 Byte, unabhängig von der Dateigröße – 50 Millionen winzige Dateien verbrennen 10–25 GB an Metadaten, bevor ein einziges Bildpixel gespeichert ist. Das Muster aus Öffnen, Lesen und Schließen legt die Metadatenseite lahm und blockiert die DataLoader-Worker.

Die Lösung liegt nicht im Dateisystem. Speichern Sie kleine Dateien nicht als Dateien. Packen Sie sie in WebDataset / Tar / Parquet / LMDB / HDF5 / Safetensors und streamen Sie sequenziell – PyTorchs WebDataset und NVIDIA DALI erwarten beide genau das. Das Dateisystem sieht dann eine kleine Zahl großer Dateien, und darin ist jedes hier genannte Dateisystem gut. Wenn Sie einzelne Dateien in großer Zahl behalten müssen, ist ZFS mit recordsize=16k und xattr=sa die am wenigsten schlechte Option – die eigentliche Antwort bleibt aber das Umpacken.

Direct I/O, Page-Cache und O_DIRECT

PyTorch stützt sich bei wiederholten Epochen über denselben Datensatz auf den Linux-Page-Cache – Epoche 1 von der Platte, Epochen 2..N aus dem RAM. Manche Workloads nutzen O_DIRECT , um den Cache bei großen Lesezugriffen zu umgehen, deren Daten nur einmal angefasst werden. NVIDIAs GPUDirect Storage geht noch weiter und überträgt per DMA direkt von der NVMe in die GPU.

ext4 und XFS setzen O_DIRECT sauber um – ausgerichteter direkter I/O, kein Page-Cache. ZFS ignoriert O_DIRECT (sämtlicher I/O läuft konstruktionsbedingt über den ARC): für die meisten Workloads unproblematisch, aber unvereinbar mit GPUDirect Storage. Die Ausrichtung ist entscheidend – Puffer und Offset müssen an der Blockgröße des Geräts ausgerichtet sein (typischerweise 4 KB).

Wenn Sie mit GPUDirect Storage eine 8-GPU-Maschine mit voller Bandbreite versorgen wollen, muss /data als XFS auf NVMe liegen. Wenn Sie nicht wissen, was GPUDirect Storage ist, und Ihr Training rechenlimitiert ist, brauchen Sie es noch nicht.

NVMe-Multipath

Dual-Port-NVMe im U.2- oder E1.S-Format meldet sich jeweils über zwei PCIe-Pfade. Der Linux-NVMe-Treiber beherrscht natives Multipathing (nvme_core.multipath=Y, in aktuellen Kerneln Standard) und bietet damit Failover und Round-Robin-Lastverteilung. Auf Dateisystemebene ist das unsichtbar, für Failover (ohne Multipathing lässt ein Pfad- oder HBA-Ausfall das Laufwerk verschwinden und das Dateisystem gerät in Panik) und Bandbreite (ein U.2-Laufwerk mit Multipathing erreicht ~14 GB/s statt 7 GB/s über einen Pfad) ist es aber relevant.

cat /sys/module/nvme_core/parameters/multipath   # erwartet: Y
nvme list-subsys

Bei Consumer-M.2-NVMe (Desktop-Builds der 5090-Klasse) spielt Multipathing keine Rolle – dort gibt es nur einen Pfad. Bei 8-GPU-EPYC-Builds mit Enterprise-U.2 oder -E1.S in einer Backplane mit zwei Controllern lassen Sie es aktiviert.

Aufwand für Prüfsummen

Operation CPU-Aufwand je GB, ein Kern Anmerkungen
ZFS fletcher4 (Standard) ~50–100 ms Standard-Prüfsumme für Datenblöcke
ZFS lz4-Kompression ~150–250 ms zahlt sich meist über weniger I/O aus
ZFS zstd-Kompression ~400–800 ms bessere Rate, höherer Aufwand
XFS / ext4 (keine Datenprüfsumme) 0 nur Metadaten

Auf einem EPYC-Host mit 64 Kernen ist dieser Aufwand unsichtbar. Auf einem 16-Kern-Xeon unter Dauerlast kann ZFS 5–10 % der effektiven CPU-Leistung kosten – ob das stört, hängt davon ab, ob das Training beim Preprocessing CPU-limitiert ist (bei Vision oft ja) oder GPU-limitiert (bei großen LLMs oft ja).

Ehrlich eingeordnet: ZFS erkennt Bit-Rot, den Sie sonst erst bemerken würden, wenn Ihr Modell auf subtil beschädigten Daten trainiert. Für einen Datensatz, an dem Sie sechs Monate gearbeitet haben, sind 5–10 % das wert. Für flüchtigen Scratch-Speicher, den Sie wöchentlich neu erzeugen, nicht.

NFS für gemeinsame Datensätze über Clusterknoten hinweg

Sobald Sie mehr als einen Server haben, wird die Frage interessant, wo der Datensatz liegt. Drei Muster:

  1. Auf jeden Knoten kopieren. Einfach, verschwendet Kapazität. Praktikabel bei <1 TB und ≤4 Knoten.
  2. NFS von einem dedizierten Storage-Server. Eine einzige maßgebliche Kopie. Das Netzwerk ist der Engpass – 25 GbE als Minimum, 100 GbE für Training über mehrere Knoten.
  3. Paralleles Dateisystem (BeeGFS, Lustre, WekaFS). Deutlich größerer Aufwand, skaliert aber über den Punkt hinaus, an dem NFS aussteigt.

Für 1–4 Knoten ist NFS richtig. Server: XFS auf NVMe im RAID10, exportiert über NFSv4. Client: mit nconnect=8 einhängen, um über mehrere TCP-Verbindungen zu parallelisieren.

# Server /etc/exports
/data/shared 10.0.10.0/24(rw,async,no_subtree_check,no_root_squash)

# Client
mount -t nfs -o vers=4.2,nconnect=8,proto=tcp,rsize=1048576,wsize=1048576 \
  storage01:/data/shared /mnt/shared

NFS über 100 GbE mit nconnect=8 liefert dauerhaft 8–10 GB/s – genug für 16 GPUs bei typischem Vision- oder LLM-Training. Darüber hinaus: BeeGFS / Lustre – ein Thema für einen eigenen Artikel.

Vollständiges Beispiel: 8-GPU-EPYC, 24 NVMe + 8 SAS

2× 480 GB NVMe  (Boot)     → md RAID1   → ext4 → /
8× 7.68 TB NVMe (Scratch)  → md RAID0   → XFS  → /scratch
8× 7.68 TB NVMe (Data)     → md RAID10  → XFS  → /data
8× 16 TB SAS    (Archiv)   → 2× RAID-Z2 → ZFS  → /archive

ZFS ARC: 64 GB von 512 GB RAM. NVMe-Multipath: an. NFS-Export: /data über 100 GbE.
mkfs.ext4 -L root /dev/md0
mkfs.xfs -f -d su=64k,sw=8 -l size=512m -L scratch /dev/md1
mkfs.xfs -f -d su=64k,sw=4 -l size=512m -L data    /dev/md2

zpool create -o ashift=12 \
  -O compression=zstd -O atime=off -O xattr=sa -O recordsize=1M \
  archive raidz2 /dev/sd[a-h]

echo "options zfs zfs_arc_max=68719476736" > /etc/modprobe.d/zfs.conf
update-initramfs -u

Roher NVMe-Durchsatz dort, wo Sie ihn brauchen, Redundanz dort, wo die Daten unersetzlich sind, und komprimierter, prüfsummengesicherter Massenspeicher für alles andere.

Wie es weitergeht

Bevor Sie irgendetwas formatieren, beantworten Sie:

  1. Wie groß ist der größte Datensatz in TB? Bestimmt die Größe von /data und sagt Ihnen, ob Sie eine Archivebene brauchen.
  2. Lassen sich die Trainingsdaten aus einer verlässlichen Quelle neu erzeugen? Wenn ja, ist RAID0 als Scratch in Ordnung. Wenn nein, mindestens RAID10, und ziehen Sie ZFS für /datain Betracht.
  3. Wie viele GPUs lesen gleichzeitig vom selben Volume? Oberhalb von etwa 8 parallelen DataLoader-Prozessen zahlen sich die Allocation Groups von XFS gegenüber ext4 aus.
  4. Brauchen Sie Snapshots? „Einen Datensatz abzweigen und zurückrollen“ → ZFS. Sonst ist XFS schneller und einfacher.
  5. Wie viel RAM steht zur Verfügung, und wie viel davon darf ZFS nehmen? Entscheiden Sie das vor der Installation, nicht nach dem ersten OOM.

Die Wahl des Dateisystems ist nicht die spannendste Entscheidung rund um einen KI-Server, aber eine der wenigen, die sich kaum rückgängig machen lässt. Wählen Sie bewusst, formatieren Sie einmal, und machen Sie weiter.


Dies ist Teil des Kentino Wiki, einer Referenzreihe zu KI-Rechenleistung, Speichertechnik und den Systemen, die beides verbinden. Kommentare und Korrekturen gerne an info@kentino.com.