Wir möchten Millionen von Textdateien in einem Linux-Dateisystem speichern, um eine beliebige Sammlung als Service komprimieren und bereitstellen zu können. Wir haben andere Lösungen ausprobiert, beispielsweise eine Schlüssel- / Wertedatenbank, aber unsere Anforderungen an Parallelität und Parallelität machen die Verwendung des nativen Dateisystems zur besten Wahl.
Am einfachsten ist es, alle Dateien in einem Ordner zu speichern:
$ ls text_files/
1.txt
2.txt
3.txt
die auf einem EXT4 Dateisystem möglich sein sollen , die keine Begrenzung der Anzahl der Dateien in einem Ordner.
Die beiden FS-Prozesse sind:
- Schreiben Sie eine Textdatei von Web Scrape (sollte nicht durch die Anzahl der Dateien im Ordner beeinflusst werden).
- Komprimieren Sie die ausgewählten Dateien anhand der Liste der Dateinamen.
Meine Frage ist, wird das Speichern von bis zu zehn Millionen Dateien in einem Ordner die Leistung der oben genannten Vorgänge oder die allgemeine Systemleistung anders beeinflussen als das Erstellen eines Unterordner-Baums für die Dateien, in denen sie gespeichert werden sollen?
quelle
dir_index
, die häufig standardmäßig aktiviert ist, beschleunigt die Suche, kann jedoch die Anzahl der Dateien pro Verzeichnis begrenzen.ls -l
oder irgendetwas anderes , dasstat
jeden Inode im Verzeichnis s (zBbash
Globbing / Tabulatorvervollständigung) wird künstlich schneller als nach einigem Verschleiß (einige Dateien löschen, einige neue schreiben). ext4 könnte hier besser abschneiden als XFS, da XFS dynamisch Speicherplatz für Inodes im Vergleich zu Daten zuweist, sodass die Inodes meines Erachtens verstreuter sind. (Aber das ist eine reine Vermutung, die auf sehr wenig detailliertem Wissen basiert. Ich habe ext4 kaum benutzt.) Gehen Sie mitabc/def/
Subdirs.ZipOutputStream
Handumdrehen erstellt werden, so gut wie jedes kostenlose native Linux-Dateisystem schlagen - ich bezweifle, dass Sie für IBMs GPFS bezahlen möchten. Die Schleife, um eine JDBC-Ergebnismenge zu verarbeiten und diesen Zip-Stream zu erstellen, besteht wahrscheinlich nur aus 6-8 Zeilen Java-Code.Antworten:
Der
ls
Befehl oder sogar die TAB-Vervollständigung oder die Platzhaltererweiterung durch die Shell zeigen ihre Ergebnisse normalerweise in alphanumerischer Reihenfolge an. Dazu muss die gesamte Verzeichnisliste gelesen und sortiert werden. Mit zehn Millionen Dateien in einem einzigen Verzeichnis nimmt dieser Sortiervorgang eine nicht zu vernachlässigende Zeit in Anspruch.Wenn Sie dem Drang der TAB-Vervollständigung widerstehen können und beispielsweise die Namen der Dateien schreiben, die vollständig komprimiert werden sollen, sollte es keine Probleme geben.
Ein weiteres Problem mit Platzhaltern könnte die Platzhaltererweiterung sein, die möglicherweise mehr Dateinamen erzeugt, als auf eine Befehlszeile mit maximaler Länge passen. Die typische maximale Befehlszeilenlänge ist für die meisten Situationen mehr als ausreichend. Wenn es sich jedoch um Millionen von Dateien in einem einzelnen Verzeichnis handelt, ist dies keine sichere Annahme mehr. Wenn eine maximale Befehlszeilenlänge bei der Platzhaltererweiterung überschritten wird, schlagen die meisten Shells einfach die gesamte Befehlszeile fehl, ohne sie auszuführen.
Dies kann gelöst werden, indem Sie Ihre Platzhalteroperationen mit dem folgenden
find
Befehl ausführen :oder eine ähnliche Syntax, wann immer dies möglich ist. Der
find ... -exec ... \+
berücksichtigt automatisch die maximale Befehlszeilenlänge und führt den Befehl so oft wie erforderlich aus, während die maximale Anzahl von Dateinamen an jede Befehlszeile angepasst wird.quelle
ls
Befehl nicht erfahren, dass die Verzeichnisliste bereits sortiert ist, werden sie sich trotzdem die Zeit nehmen, um den Sortieralgorithmus auszuführen. Außerdem verwendet der Userspace möglicherweise eine lokalisierte Sortierreihenfolge (LC_COLLATE), die sich möglicherweise von der internen Vorgehensweise des Dateisystems unterscheidet.Dies kommt einer meinungsbasierten Frage / Antwort gefährlich nahe, aber ich werde versuchen, einige Fakten mit meinen Meinungen zu versehen.
mv * /somewhere/else
), den Platzhalter nicht erfolgreich erweitern, oder das Ergebnis ist möglicherweise zu groß für die Verwendung.ls
Das Auflisten einer sehr großen Anzahl von Dateien dauert länger als das Auflisten einer kleinen Anzahl von Dateien.Eine Empfehlung besteht darin, den Dateinamen in zwei, drei oder vier Zeichenblöcke aufzuteilen und diese als Unterverzeichnisse zu verwenden. Zum Beispiel
somefilename.txt
könnte gespeichert werden alssom/efi/somefilename.txt
. Wenn Sie numerische Namen verwenden, teilen Sie diese von rechts nach links statt von links nach rechts, um eine gleichmäßigere Verteilung zu erzielen. Zum Beispiel12345.txt
könnte als gespeichert werden345/12/12345.txt
.Sie können das Äquivalent von verwenden
zip -j zipfile.zip path1/file1 path2/file2 ...
, um zu vermeiden, dass die Zwischenpfade des Unterverzeichnisses in die ZIP-Datei aufgenommen werden.Wenn Sie diese Dateien von einem Webserver aus bereitstellen (ich bin mir nicht ganz sicher, ob das relevant ist), ist es trivial, diese Struktur zugunsten eines virtuellen Verzeichnisses mit Umschreiberegeln in Apache2 auszublenden. Ich würde davon ausgehen, dass dies auch für Nginx gilt.
quelle
*
Erweiterung ist erfolgreich, es sei denn, Sie haben nicht genügend Arbeitsspeicher. Wenn Sie jedoch das Stapelgrößenlimit erhöhen (unter Linux) oder eine Shell verwenden, in die bereits etwas integriertmv
ist oder integriert werden kann (ksh93, zsh), schlägt derexecve()
Systemaufruf möglicherweise mit einem E2BIG-Fehler fehl.zip -j - ...
den Ausgabestream direkt über die Netzwerkverbindung des Clients zu verwenden und weiterzuleitenzip -j zipfile.zip ...
. Wenn Sie eine aktuelle Zip-Datei auf die Festplatte schreiben, wird der Datenpfad von der Festplatte gelesen -> komprimieren -> auf die Festplatte schreiben -> von der Festplatte lesen -> an den Client senden. Damit können Sie Ihre Festplatten-E / A-Anforderungen verdreifachen, indem Sie Daten von Festplatte-> Komprimieren-> An Client senden.Ich betreibe eine Website, die eine Datenbank für Filme, Fernsehen und Videospiele verwaltet. Für jedes dieser Bilder gibt es mehrere Bilder mit einem Fernseher, die Dutzende von Bildern pro Show enthalten (z. B. Episodenschnappschüsse usw.).
Am Ende stehen viele Bilddateien. Irgendwo im Bereich von 250.000+. Diese werden alle in einem eingebauten Blockspeicher gespeichert, bei dem die Zugriffszeit angemessen ist.
Mein erster Versuch, die Bilder zu speichern, war in einem einzigen Ordner als
/mnt/images/UUID.jpg
Ich bin auf die folgenden Herausforderungen gestoßen.
ls
über ein fernterminal würde nur hängen bleiben. Der Prozess würde zum Zombie werden undCTRL+C
ihn nicht brechen.ls
würde jeder Befehl schnell den Ausgabepuffer füllen undCTRL+C
das endlose Scrollen nicht stoppen.Schließlich musste ich die Dateien in Unterordnern speichern, wobei ich die Erstellungszeit zum Erstellen des Pfads verwendete. Wie
/mnt/images/YYYY/MM/DD/UUID.jpg
. Dadurch wurden alle oben genannten Probleme behoben, und ich konnte ZIP-Dateien erstellen, die auf ein Datum abzielten.Wenn die einzige Kennung für eine Datei eine numerische Nummer ist, werden diese Nummern in der Regel nacheinander ausgeführt. Warum nicht gruppieren sie durch
100000
,10000
und1000
.Wenn Sie beispielsweise eine Datei mit dem Namen haben, lautet
384295.txt
der Pfad:Wenn Sie wissen, werden Sie einige Millionen erreichen. Verwenden Sie
0
Präfixe für 1.000.000quelle
Um eine neue Datei zu erstellen, muss die Verzeichnisdatei nach ausreichend freiem Speicherplatz für den neuen Verzeichniseintrag durchsucht werden. Wenn sich kein Speicherplatz befindet, der groß genug ist, um den neuen Verzeichniseintrag zu speichern, wird er am Ende der Verzeichnisdatei platziert. Wenn die Anzahl der Dateien in einem Verzeichnis zunimmt, nimmt auch die Zeit zum Durchsuchen des Verzeichnisses zu.
Solange die Verzeichnisdateien im Systemcache verbleiben, wird die Leistung dadurch nicht beeinträchtigt. Wenn die Daten jedoch freigegeben werden, kann das Lesen der Verzeichnisdatei (normalerweise stark fragmentiert) von der Festplatte einige Zeit in Anspruch nehmen. Eine SSD verbessert dies, aber für ein Verzeichnis mit Millionen von Dateien kann es immer noch zu einer spürbaren Leistungsbeeinträchtigung kommen.
Dies erfordert wahrscheinlich auch zusätzliche Zeit in einem Verzeichnis mit Millionen von Dateien. In einem Dateisystem mit gehashten Verzeichniseinträgen (wie EXT4) ist dieser Unterschied minimal.
Ein Baum von Unterordnern weist keine der oben genannten Leistungsnachteile auf. Wenn das zugrunde liegende Dateisystem so geändert wird, dass es keine Hash-Dateinamen hat, funktioniert die Baummethode weiterhin gut.
quelle
Erstens: Verhindern Sie, dass 'ls' mit 'ls -U' sortiert, und aktualisieren Sie Ihren ~ / bashrc möglicherweise mit 'alias ls = "ls -U"' oder ähnlichem.
Für Ihre große Dateigruppe können Sie dies folgendermaßen ausprobieren:
Erstellen Sie eine Reihe von Testdateien
Überprüfen Sie, ob viele Dateinamen Probleme verursachen
Verwenden Sie das Parmeter-Batching von xargs und das (Standard-) Verhalten von zip zum Hinzufügen von Dateien zu einer Zip, um Probleme zu vermeiden.
Das hat gut funktioniert:
quelle