Valg af filsystem til AI-servere: XFS, ZFS, ext4 og hvorfor Btrfs ikke er på listen
Hvis du lige har brugt €40 på GPU'er, fortjener det filsystem, du hælder dine data på, mere end fem minutters overvejelse. Ubuntu-installationsprogrammet lægger gladeligt ext4 på tværs af alt; for mange AI-arbejdsbelastninger er det det rigtige svar, for nogle er det ikke. Vælg det forkerte filsystem til en datasætvolumen på 50 TB, og du mister gennemløb, mister data eller ser din DataLoader sidde inaktiv bag en metadata-flaskehals.
Dette dækker hvilket filsystem der skal placeres hvor på en Kentino-klasse AI-server (4-8 GPU'er, NVMe-opstart, NVMe scratch, langsommere bulk-niveau). Ubuntu 22.04 / 24.04, 6.x kerne.
Den korte version
| Monteringspunkt | arbejdsbyrde | Filsystem | Hvorfor |
|---|---|---|---|
/ (opstart, rod) |
OS, pakker, logfiler | ext4 | Kedeligt, bevist, genopretteligt |
/scratch (NVMe RAID0) |
Aktive træningsskår, flygtige skriverier | XFS | Gennemløb, parallel mappe-I/O |
/data (RAID10) |
Træningsdatasæt, modelkontrolpunkter | XFS eller ZFS | XFS for rå hastighed; ZFS hvis du vil have snapshots + checksummer |
/archive (RAID-Z2/6) |
Færdige kørsler, kold opbevaring af datasæt | ZFS | Komprimering, checksummer, snapshots |
/home |
Brugerhjem, notesbøger | ext4 | Små filer, lav konkurrence |
Version med ét afsnit: ext4 til operativsystemet, XFS til hot scratch, ZFS hvor integritet er vigtigere end de sidste 10% af gennemløbet, ingen Btrfs i produktion.
ext4 — den kedelige standardværdi, der normalt er rigtig
ext4 har været standard på Ubuntu, Debian, Fedora og RHEL i over et årti. Velforstået, kan gendannes med fsck, 16 TB pr. fil, 1 EB pr. volumen. Intet spændende — pointen.
Brug ext4 til root (alle Ubuntu live USB ved, hvordan man retter det; langt færre ved, hvordan man importerer en zpool), f.eks. /homeog til VM-billedlagre i lille til mellemstor skala.
Hvor ext4 ikke længere har ret: bred parallel I/O (dens journal serialiserer metadataopdateringer — tyve DataLoader-arbejdere på én ext4-volumenflaskehals i journalen længe før den mætter NVMe); enkelte store filer (håndteres, men extent-allokering er mindre brugervenlig end XFS for sekventielle filer >100 GB — træningsshards, checkpoints, videokorpora); snapshots (ingen native; LVM-tynde snapshots fungerer, men er klodsede).
mkfs.ext4 -L root /dev/nvme0n1p2
Hvis du finder dig selv i gang med eksotisk ext4-tuning til en AI-arbejdsbelastning, har du valgt det forkerte filsystem.
XFS — det rigtige svar til hot scratch- og træningsdata
XFS var et SGI-filsystem til sekventiel I/O med høj kapacitet på store arrays. Denne arv matcher næsten perfekt AI-arbejdsbelastninger: store filer (træningsshards, parquet, webdataset-tars, checkpoints), sekventielle læsninger, mange parallelle læsere, tolerance for "arbejdsbelastningen regenererer dataene".
Hvad XFS gør, som ext4 ikke gør: allokeringsgrupper — volumenet opdeles i 4-32 uafhængige grupper, der læser og skriver parallelt uden en global journallås, præcis hvad en DataLoader med flere medarbejder ønsker; forsinket og spekulativ forhåndsallokering så store sekventielle skrivninger får sammenhængende omfang; ingen praktisk grænse for filstørrelse (8 EB); og xfs_growfs for pålidelig one-liner-udvidelse efter RAID-vækst.
Hvad den ikke gør: ingen native snapshots, ingen fildata-checksums (metadata CRC-beskyttet siden 2014), ingen krympning - kun voksning.
En rimelig mkfs.xfs for en 8× NVMe RAID0 scratch-volumen, 64 KiB chunk:
# su = stripe unit = chunk size; sw = number of data disks
mkfs.xfs -f -d su=64k,sw=8 -l size=512m -L scratch /dev/md0
# largeio + swalloc: behave for >1 MB I/O
# allocsize=1g: preallocate aggressively for big sequential writes
# noatime: save a write per read under heavy DataLoader load
mount -o noatime,largeio,swalloc,allocsize=1g /dev/md0 /scratch
noatime og largeio betyder mest. XFS på små filer er acceptabelt, men ikke dets stærke side — for hundredvis af millioner af billeder på <16 KB, pak om til webdataset / parquet / lmdb i stedet for at bytte filsystemer (se nedenfor).
ZFS — det rigtige svar, når integritet, snapshots eller komprimering er vigtige
ZFS er et filsystem, en volumenhåndtering og et software-RAID-lag i ét:
- End-to-end checksumming. Bitrot registreret ved læsning, korrigeret lydløst med redundans. For et 50 TB datasæt på spinning rust i to år er dette vigtigt; for kortvarig NVMe scratch i over seks uger er det ikke relevant.
- Snapshots og kloner. Atomic, COW, effektivt fri. Snapshot før en kørsel, forgrening af en klon, rollback – den arbejdsgang ZFS eksisterer for.
-
Indbygget kompression.
lz4standard-til;zstdfor bedre forhold. På tekst / JSON / parquet er komprimering normalt stigninger effektiv gennemløbshastighed, fordi CPU-omkostningerne er mindre end den sparede I/O. - ARC — sin egen RAM-baserede læsecache, adskilt fra Linux-sidecachen. Den berømte footgun.
- Native RAID-Z — nej mdadm.
Hvad det ikke gør godt for AI: spiser RAM (standard ARC er ~50% af systemhukommelsen — på en 512 GB server, der er 256 GB, har kernen pludselig ikke mere, og træningsjob, der forventer sidecache eller store sider, bliver OOM-dræbt; læg en grænse for ARC'en); ikke den hurtigste for rå sekventielle læsninger (veltunet XFS på NVMe RAID0 slår ZFS med 15-30% — checksumming og COW-omkostninger i reelle cyklusser); ignorerer O_DIRECT (al I/O via ARC efter design — fint til de fleste arbejdsbelastninger, en hård inkompatibilitet med GPUDirect Storage).
ARC-tuning — den ene knap, du skal indstille
På en frisk Ubuntu + ZFS-installation på en 512 GB-boks gør ZFS krav på 256 GB til ARC. zfs_arc_max ved installation, ikke efter den første OOM.
# Cap ARC at 64 GB. Bytes, not 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 # apply now
sudo update-initramfs -u # persist
Tommelfingerregel: Begræns ARC til 10-20% af system-RAM på en AI-server. Den klassiske størrelsesorden "2 GiB base + 1 GiB pr. TiB" er til storage boxes; på en AI-box er det meste RAM reserveret til modelvægte, aktiveringer og framework-sidecache.
Et fornuftigt ZFS-layout til et AI-serverdatalag
# 8 × 16 TB SAS in two RAID-Z2 vdevs (6+2 each) — two vdevs give 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 sized for their workload
zfs create -o recordsize=1M data/datasets # large training shards
zfs create -o recordsize=128k data/checkpoints # mixed size
zfs create -o recordsize=16k data/metadata # small files (json, yaml)
zfs snapshot data/datasets@pre-run-2026-05-14
zfs rollback data/datasets@pre-run-2026-05-14
ashift=12 = 4 KiB-blokke — hvis du gør dette forkert ved oprettelsen af puljen, kan du ikke rette det uden at ødelægge puljen. recordsize=1M til arbejdsbelastninger med store filer (standard 128 KiB er for lille til shards på flere GB). xattr=sa gemmer xattrs inline, massivt hurtigere end standarden.
Btrfs — undgås generelt til produktions-AI
Btrfs har de samme konceptuelle funktioner som ZFS — COW, snapshots, checksums, indbygget RAID. På papiret, ikke sandt; i praksis anbefaler vi det ikke på Kentino-servere. RAID5/6 har kendte datatabsfejl, som projektet selv markerer som ikke produktionsklar (RAID1/10 er stabile, paritetstilstande er ikke); ydeevnen forringes kraftigt under det fragmenteringsmønster, som AI-arbejdsbelastninger producerer (gradient checkpoints, caches); snapshot-ydeevnen falder drastisk over et par hundrede snapshots, som en arbejdsgang pr. eksperiment rammer inden for et kvartal; og værktøjerne er mindre modne end ZFS eller XFS til replikering, overvågning og scrub-planlægning. Fint på en bærbar computer. For en multi-GPU-server med snesevis af TB træningsdata, vælg XFS eller ZFS.
RAID-layouts — hvad skal filsystemet parres med
| RAID-niveau | Brug sag | Redundans | Noter |
|---|---|---|---|
| RAID0 | Scratch (flygtig, regenererbar) | Ingen | Kun for data, du kan genopbygge |
| RAID10 | Træningsdatasæt, kontrolpunkter | 1 pr. spejl | Bedste hastighed + sikkerhed til hot data |
| RAID-Z1 / RAID5 | Undgå ved nybyggeri | 1 disk | Genopbygningstider på 16 TB+ drev gør Z1 risikabelt |
| RAID-Z2 / RAID6 | Arkiv, kold datalagring | 2 diske | Det rigtige valg til store mængder |
| RAID-Z3 | Brede arrays (12+ diske) | 3 diske | Kun når arraybredden tvinger det |
På drev på 16 TB+ kan en genopbygning af en enkelt disk tage 24-72 timer, og en anden fejl på tværs af drev med samme batch i det vindue er ikke ubetydelig. Enkeltparitet er ikke længere den sikre standard. Brug Z2/RAID6 eller filspejle.
Små filer versus store filer
Spørgsmålet, der fanger folk mere end noget andet filsystemvalg: hvordan opfører dit filsystem sig med 50 millioner 4 KB-billeder i et mappetræ? Svaret for alle filsystemer her: dårligt.
Metadata pr. fil (inode, dentry, timestamps, xattrs) kører 200-500 bytes uanset filstørrelse — 50 millioner små filer brænder 10-25 GB metadata, før de lagrer en byte pixeldata. Åbn/læs/luk-mønsteret binder metadatasiden og blokerer DataLoader-workers.
Løsningen er ikke filsystemet. Gem ikke små filer som filer. Pak ind i webdataset / tar / parquet / lmdb / hdf5 / safetensors og stream sekventielt — PyTorch's WebDataset og NVIDIA DALI forventer begge dette. Filsystemet ser derefter et lille antal store filer, hvilket alle filsystemer her er gode til. Hvis du skal holde individuelle filer i stor skala, ZFS med recordsize=16k og xattr=sa er den mindst dårlige løsning, men den virkelige løsning er at pakke om.
Direkte I/O, sidecache og O_DIRECT
PyTorch bruger Linux-sidecachen til gentagne datasæt-epoker — epoke 1 fra disk, epoker 2..N fra RAM. Nogle arbejdsbelastninger bruger O_DIRECT at omgå cachen ved store læsninger, hvor data kun berøres én gang. NVIDIAs GPUDirect-lagring går endnu videre og bruger DMA'er til at NVMe → GPU direkte.
ext4 og XFS ære O_DIRECT korrekt — justeret direkte I/O, ingen sidecache. ZFS ignorerer O_DIRECT (al I/O via ARC, per design): fint til de fleste arbejdsbelastninger, en hård inkompatibilitet med GPUDirect Storage. Justering er vigtig — buffer og offset skal justeres til enhedens blokstørrelse (typisk 4 KB).
Hvis du planlægger at bruge GPUDirect Storage til at forsyne en 8-GPU-boks med fuld båndbredde, /data skal være XFS på NVMe. Hvis du ikke ved, hvad GPUDirect Storage er, og træning er computerbundet, har du ikke brug for det endnu.
NVMe-multipath
Dual-port U.2 / E1.S NVMe præsenteres som to PCIe-stier hver. Linux NVMe-driveren bruger native multipath (nvme_core.multipath=Y, standard i moderne kerner), hvilket giver failover og round-robin load balancing. Usynlig på filsystemlaget, men den har betydning for failover (uden den får en sti-/HBA-fejl drevet til at forsvinde, og filsystemet går i panik) og båndbredde (et U.2-drev med flere stier når ~14 GB/s versus 7 GB/s med én sti).
cat /sys/module/nvme_core/parameters/multipath # expect: Y
nvme list-subsys
For forbruger M.2 NVMe (5090 desktop-klasse builds) er multipath ikke relevant – én sti. For 8-GPU EPYC builds med Enterprise U.2 / E1.S i et backplane med to controllere, skal den lades være aktiveret.
Overhead for checksum
| Produktion | CPU-pris pr. GB, én kerne | Noter |
|---|---|---|
| ZFS fletcher4 (standard) | ~50–100 ms | Standard datablok checksum |
| ZFS lz4 komprimering | ~150–250 ms | Betaler sig normalt tilbage via reduceret I/O |
| ZFS zstd komprimering | ~400–800 ms | Bedre forhold, højere omkostninger |
| XFS / ext4 (ingen datakontrolsum) | 0 | Kun metadata |
På en 64-core EPYC-vært er omkostningerne usynlige. På en 16-core Xeon under vedvarende belastning kan ZFS stjæle 5-10% af den effektive CPU - om det betyder noget afhænger af, om træningen er CPU-bundet til forbehandling (ofte ja for vision) eller GPU-bundet (ofte ja for store LLM'er).
Den ærlige fremstilling: ZFS fanger bitrot, som du ellers aldrig ville bemærke, før din model træner på subtilt korrupte data. For et datasæt, du har brugt seks måneder på at opbygge, er 5-10% det værd. For ephemer scratch, som du regenererer ugentligt, er det ikke tilfældet.
NFS til delte datasæt på tværs af klyngenoder
Når du har mere end én server, bliver det interessant, hvor datasættet befinder sig. Tre mønstre:
- Kopiér til hver node. Simpelt, spilder kapacitet. Kan bruges til <1 TB og ≤4 noder.
- NFS fra en dedikeret lagringsserver. Én kanonisk kopi. Netværket er flaskehalsen — minimum 25 GbE, 100 GbE til træning med flere noder.
- Parallelt filsystem (BeeGFS, Lustre, WekaFS). Større løft, skalerer forbi hvor NFS falder over.
For 1-4 noder er NFS korrekt. Server: XFS på RAID10 NVMe, eksporteret via NFSv4. Klient: monter med nconnect=8 at parallelisere på tværs af TCP-forbindelser.
# 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 over 100 GbE med nconnect=8 leverer 8-10 GB/s vedvarende — nok til 16 GPU'er på typisk vision- eller LLM-træning. Udover det, BeeGFS / Lustre — en anden artikel.
Komplet eksempel: 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 (archive) → 2× RAID-Z2 → ZFS → /archive
ZFS ARC: 64 GB of 512 GB RAM. NVMe multipath: on. NFS export: /data over 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
Rå NVMe-gennemstrømning, hvor du har brug for det, redundans, hvor dataene er uerstattelige, komprimeret checksum-bulk til alt andet.
Hvad skal jeg gøre næste
Før du formaterer noget, skal du svare på:
-
Største datasæt, i TB? Størrelser
/dataog fortæller dig, om du har brug for et arkivniveau. -
Kan træningsdata regenereres fra en sandhedskilde? Hvis ja, er RAID0 fra bunden fint. Hvis nej, RAID10 minimum, overvej ZFS på
/data. - Hvor mange GPU'er læser den samme mængde samtidigt? Over ~8 parallelle DataLoader-processer betaler XFS's allokeringsgrupper tilbage i forhold til ext4.
- Har du brug for øjebliksbilleder? "Fork et datasæt og rul tilbage" → ZFS. Ellers er XFS hurtigere og enklere.
- RAM-budget, og hvor meget kan ZFS klare? Beslut dig før installation, ikke efter den første OOM.
Valg af filsystem er ikke den mest interessante beslutning, man træffer om en AI-server, men det er en af de få, der virkelig er svære at omgøre. Vælg bevidst, formater én gang, og kom videre.
Dette er en del af Kentino Wiki, en referenceserie om AI-beregning, lagring og de systemer, der forbinder dem. Kommentarer og rettelser er velkomne på info@kentino.com.