TL;DR
Die Dateianzahl allein ist nutzlos für die Zeitschätzung einer Migration. Entscheidend ist die Größenverteilung: Millionen kleiner Dateien sind IOPS-limitiert, große Dateien sind Throughput-limitiert. Profiliere dein Dataset zuerst, dann schätze jede Portion separat. syncopios Discovery-Scan profiliert dein Dataset automatisch und die Assessment-Phase liefert dir verlässliche Transfer-Zeitschätzungen basierend auf echten Benchmarks — kein Rätselraten.
Dein Chef fragt: “Wie lange dauert die Migration?” Du prüfst die Dateianzahl. 1,2 Millionen Dateien. Du schätzt vier Stunden. Es dauert neunzehn.
Oder andersherum. Du sagst deinem Chef neunzehn Stunden, blockierst das Wochenende, verschickst die Wartungsankündigung an 400 User. Die Migration ist nach zwei Stunden fertig. Du wirkst, als hättest du keine Ahnung, was du tust.
Beides passiert, weil die Dateianzahl allein eine nutzlose Zahl ist. Sie sagt dir fast nichts darüber, wie lange die Migration tatsächlich dauern wird.
Hier liegt das Problem. “1,2 Millionen Dateien” kann bedeuten:
Gleiche Dateianzahl. Völlig andere Workloads. Völlig andere Zeitpläne. Völlig andere Engpässe.
Die Zahl, die wirklich zählt, ist die Größenverteilung: Wie viele Dateien fallen in welche Größenklasse, und wie viele Bytes entfallen auf jede Klasse?
Die bimodale Falle
Reale Datasets sind fast nie gleichmäßig verteilt. Ein typisches NAS hat Millionen winziger Dateien (Thumbnails, Metadaten, Logs) UND eine Handvoll riesiger Dateien (Datenbank-Dumps, Video-Archive, VM-Images). Die kleinen Dateien dominieren die Anzahl. Die großen Dateien dominieren die Bytes. Für das eine zu planen und das andere zu ignorieren, garantiert eine schlechte Schätzung.
Wenn der Großteil deiner Daten aus kleinen Dateien (unter 128 KB) besteht, ist der eigentliche Datentransfer trivial. Eine Gigabit-Leitung schiebt 5 GB in unter einer Minute durch. Daran liegt es nicht.
Jede Datei erfordert:
open() auf der Quellestat() für Metadatenopen() + create() auf dem Zielwrite() der Daten (schnell, ist ja winzig)chmod() für Berechtigungenchtimes() für Timestampsclose() auf beiden SeitenMindestens sieben Syscalls pro Datei. Über NFS ist jeder davon ein Netzwerk-Round-Trip. Bei 1 ms pro Round-Trip (typisch im lokalen 10-GbE-Netz; bei Cross-Site-Links oder ausgelasteten Speichern eher 5–20 ms) sind das 7 ms pro Datei. Multipliziert mit einer Million Dateien: fast zwei Stunden reiner Overhead, bei kaum Datenvolumen.
Workloads mit kleinen Dateien sind IOPS-limitiert. Festplatte und Netzwerk schaffen die Bytes locker. Sie ersticken an den Operationen. Dein NAS schafft vielleicht 10.000 IOPS. Deine Million kleiner Dateien braucht 7 Millionen Operationen. Das sind fast 12 Minuten allein an IOPS, bei null Contention. In der Praxis, mit Metadaten-Journaling und Verzeichnis-Updates, verdreifache das.
Hinweis: Das sind zwei separate Engpässe — NFS-Netzwerklatenz und Storage-IOPS — und der schlimmere von beiden bestimmt dein tatsächliches Limit. Im lokalen LAN dominieren meist die Storage-IOPS. Über ein WAN die Netzwerklatenz.
Schnelldiagnose
Wenn du -sh 50 GB sagt, aber find | wc -l 2 Millionen Dateien, bist du IOPS-limitiert. Parallele Worker helfen hier mehr als Bandbreite.
Dreh es um. Du hast 50.000 Dateien mit durchschnittlich 2 GB. Das sind 100 TB. Der Per-File-Overhead ist vernachlässigbar: 50.000 Opens und Closes sind nichts. Der Engpass ist der reine Durchsatz.
Auf einer 10-Gbps-Leitung liegt das theoretische Maximum bei etwa 1,1 GB/s. In der Praxis, mit NFS-Overhead, siehst du 400 bis 700 MB/s. Bei 500 MB/s dauern deine 100 TB etwa 55 Stunden. Keine IOPS-Optimierung ändert diese Zahl. Du brauchst schnellere Leitungen oder mehrere parallele Streams pro Datei.
Workloads mit großen Dateien sind durchsatzlimitiert. Mehr Worker helfen kaum, es sei denn, jeder Worker kann seinen eigenen Stream auslasten. Was hilft: größere TCP-Windows, größere NFS Read/Write-Sizes (rsize/wsize) und sicherstellen, dass dein Netzwerk nicht der Flaschenhals ist.
Hier ein realistisches Beispiel von einem mittelgroßen Engineering-NAS:
| Größenklasse | Dateien | % der Anzahl | Bytes | % der Bytes |
|---|---|---|---|---|
| < 4 KB | 380.000 | 31,7 % | 0,8 GB | 0,1 % |
| 4 KB bis 128 KB | 290.000 | 24,2 % | 12 GB | 1,0 % |
| 128 KB bis 10 MB | 340.000 | 28,3 % | 420 GB | 34,4 % |
| 10 MB bis 1 GB | 185.000 | 15,4 % | 490 GB | 40,2 % |
| 1 GB bis 100 GB | 4.800 | 0,4 % | 296 GB | 24,3 % |
| > 100 GB | 12 | 0,001 % | 2,4 TB | — |
Schau dir diese Zahlen an. 56 % der Dateien sind kleiner als 128 KB und machen gerade mal 1 % der Daten aus. Gleichzeitig entfallen auf 0,4 % der Dateien (die 1-GB+-Klasse) fast ein Viertel der Bytes. Deine Zeitschätzung muss beide Workloads berücksichtigen, die gleichzeitig laufen.
Bevor du dich auf ein Cutover-Fenster festlegst, führe diese Befehle auf der Quelle aus. Dauert ein paar Minuten, erspart dir eine schlechte Schätzung.
Schnelle Dateianzahl nach Größenklasse:
find /path/to/data -type f -printf '%s\n' | awk '
{ s=$1;
if (s < 4096) { a++; ab+=s }
else if (s < 131072) { b++; bb+=s }
else if (s < 10485760) { c++; cb+=s }
else if (s < 1073741824){ d++; db+=s }
else { e++; eb+=s }
total += s;
}
END {
g=1073741824;
printf "< 4KB: %8d files %8.1f GB\n", a, ab/g;
printf "4K-128K: %8d files %8.1f GB\n", b, bb/g;
printf "128K-10M: %8d files %8.1f GB\n", c, cb/g;
printf "10M-1G: %8d files %8.1f GB\n", d, db/g;
printf "> 1GB: %8d files %8.1f GB\n", e, eb/g;
printf "\nTotal: %d files, %.1f GB\n", a+b+c+d+e, total/g;
}'
Top 20 der größten Dateien (dein Durchsatz-Engpass):
find /path/to/data -type f -printf '%s %p\n' | sort -rn | head -20
Verzeichnis mit den meisten Dateien (dein IOPS-Hotspot):
# Achtung: langsam bei großen Verzeichnisbäumen — startet eine Subshell pro Verzeichnis.
# Bei 100K+ Verzeichnissen kannst du mit 10-30 Minuten rechnen. Lohnt sich trotzdem.
find /path/to/data -type d -exec sh -c 'echo "$(find "$1" -maxdepth 1 -type f | wc -l) $1"' _ {} \; | sort -rn | head -10
syncopio advantage
Keine Lust, das manuell auszuführen? syncopios Discovery-Scan profiliert dein gesamtes Dataset automatisch — Dateianzahlen nach Größenklasse, IOPS-Hotspots und Transfer-Schätzungen pro Klasse — bevor du dich auf ein Cutover-Fenster festlegst.
Warum Verzeichnisse auch zählen
Ein einzelnes Verzeichnis mit 500.000 Dateien ist dramatisch langsamer zu verarbeiten als 500 Verzeichnisse mit je 1.000 Dateien. Verzeichnis-Lookups in großen Verzeichnissen sind nicht O(1). Auf ext4/XFS sind sie beim ersten Zugriff, bevor der Dentry-Cache aufgewärmt ist, ungefähr O(n). Über NFS gibt jeder readdir-Aufruf nur eine begrenzte Anzahl Einträge zurück, sodass das Auflisten eines 500K-Eintrags-Verzeichnisses hunderte Round-Trips erfordert.
Wenn du deine Verteilung kennst, kannst du die Migration richtig tunen.
Überwiegend kleine Dateien (IOPS-limitiert):
noatime-Mount-Optionen in Betracht ziehen, um Metadaten-Writes zu reduzieren.Überwiegend große Dateien (durchsatzlimitiert):
rsize/wsize auf 1 MB erhöhen (Standard ist oft 64 KB oder 256 KB).iperf3 prüfen. Wenn die Leitung die Rate nicht halten kann, verursachen mehr Worker nur Congestion.Gemischt (bimodal):
max(kleine_dateien_zeit, große_dateien_zeit), nicht die Summe, wenn du parallelisieren kannst.syncopio advantage
syncopio passt Worker-Anzahl und Puffergrößen automatisch an die Größenverteilung deines Datasets an. Du gibst das Ziel vor, syncopio wählt die Konfiguration. So funktioniert es →
Das wird nicht perfekt, aber es ist besser als eine Schätzung allein auf Basis der Dateianzahl.
Für den Kleindateien-Anteil:
time_small = (dateianzahl × ops_pro_datei × latenz_pro_op) / parallele_worker
Aus der Tabelle oben: 670.000 Dateien unter 128 KB, 7 Ops pro Datei, 1,5 ms durchschnittliche NFS-Latenz, 8 Worker:
(670.000 × 7 × 0,0015) / 8 = 879 Sekunden ≈ 15 Minuten
Für den Großdateien-Anteil:
time_large = bytes_gesamt / (durchsatz_pro_stream × parallele_streams)
Aus der Tabelle: ~786 GB in Dateien über 10 MB, 400 MB/s pro Stream, 4 Streams:
786.000 MB / (400 × 4) = 491 Sekunden ≈ 8 Minuten
Gesamtschätzung: max(15, 8) = etwa 15 Minuten, wenn beides parallel läuft. Addiere 20 bis 30 % für Overhead (Verzeichniserstellung, Retries, Verifizierung). Nenne es 20 Minuten.
Vergleiche das mit der naiven Schätzung: “1,2 Millionen Dateien bei 2.000 Dateien/Sekunde = 10 Minuten.” Hier um den Faktor 2 daneben — und bei einem anderen Dataset könnte die naive Schätzung um den Faktor 5 daneben liegen.
syncopio advantage
syncopios Discovery-Scan profiliert dein Dataset vor dem Transfer. Er zeigt die Dateianzahl nach Größenklasse, identifiziert IOPS-Hotspots (Verzeichnisse mit hoher Dateianzahl) und berechnet Transfer-Schätzungen pro Klasse. Du siehst die Verteilung, bevor du dich auf ein Cutover-Fenster festlegst — nicht danach. Kostenlosen Discovery-Scan starten →
Schätzungs-Cheat-Sheet
find | awk-Skript oben aus, um Dateianzahlen und Bytes pro Größenklasse zu ermitteln.(dateien_unter_128KB × 7 × latenz_ms) / worker — nimm 1,5 ms für lokales NFS, 5–20 ms für Cross-Site.bytes_über_10MB / (durchsatz × streams) — nimm 400 MB/s pro Stream als konservativen Startwert.max(klein, groß) × 1,3 — die 30 % decken Verzeichniserstellung, Retries und Verifizierung ab.iperf3 zwischen Quelle und Ziel. Wenn die Leitung deinen Throughput-Schätzwert nicht halten kann, ist das dein tatsächliches Limit.Wenn dein Chef das nächste Mal fragt, sag nicht “1,2 Millionen Dateien.” Sag stattdessen:
Zum Kopieren für deine nächste Status-Mail
“Das Dataset umfasst 1,2 Millionen Dateien mit insgesamt 1,2 TB. Basierend auf der Größenverteilung sind ca. 670K Dateien Kleindateien-Overhead (IOPS-limitiert, ~15 Min.) und 786 GB stecken in großen Dateien (durchsatzlimitiert, ~8 Min. bei 400 MB/s × 4 Streams). Geschätzte Transferzeit: 20 Minuten, plus 30 % Puffer für die Verifizierung. Nach dem Discovery-Scan habe ich eine genauere Zahl.”
Das ist eine Antwort, die du verteidigen kannst. “1,2 Millionen Dateien” ist es nicht.
Dein Chef muss nicht verstehen, was IOPS oder Throughput sind. Er muss sehen, dass du das Problem aufgeschlüsselt hast, den Engpass identifiziert hast und eine Zahl hast, die auf echten Daten basiert. Das Profilieren dauert fünf Minuten. Die Glaubwürdigkeit, die es dir bringt, ist den Aufwand wert.
Weiterführende Lektüre:
rsize/wsize und Mount-Optionen)