Leistung / Stabilität eines Memory Mapped-Datei - Muttersprache oder MappedByteBuffer - vs. plain ol‘Fileoutputstream

StackOverflow https://stackoverflow.com/questions/537295

Frage

Ich unterstütze eine ältere Java-Anwendung, die flachen Dateien (Klartext) für die Persistenz verwendet. Aufgrund der Art der Anwendung kann die Größe dieser Dateien 100s MB pro Tag erreichen und oft der limitierende Faktor bei der Anwendungsleistung ist IO-Datei. Derzeit verwendet die Anwendung ein einfaches ol java.io.FileOutputStream, um Daten auf die Festplatte zu schreiben.

Vor kurzem haben wir hatten mehrere Entwickler behaupten, dass Dateien Memory-Mapped Verwendung in nativen Code implementiert (C / C ++) und über JNI zugegriffen wird, eine höhere Leistung bieten würde. Allerdings Outputstream bereits verwendet native Methoden für ihre Kernverfahren (das heißt write (byte [])), so scheint es, eine dürftige Annahme ohne harte Daten oder zumindest anekdotische Evidenz.

Ich habe mehrere Fragen zu diesem Thema:

  1. Ist diese Behauptung wirklich wahr? Wird im Speicher abgebildeten Dateien immer eine schnellere IO im Vergleich zu Java Fileoutputstream?

  2. Ist die Klasse MappedByteBuffer von einem Filechannel zugegriffen bereitzustellen die gleiche Funktionalität wie eine native Memory-Mapped-Datei Bibliothek zugegriffen über JNI? Was ist MappedByteBuffer dass fehlen könnte führen Sie ein verwenden JNI Lösung?

  3. Was sind die Risiken der Verwendung von Memory-Mapped-Dateien für die Disk IO in einer Produktions Anwendung? Das heißt, Anwendungen die haben kontinuierliche Verfügbarkeit mit minimal Neustarts (einmal im Monat, max). Real-Life-Anekdoten aus der Produktion Anwendungen (Java oder auf andere Weise) bevorzugt.

Frage # 3 ist wichtig - ich diese Frage selbst beantworten kann teilweise durch eine „Spielzeug“ Anwendung zu schreiben, die IO-perf-Tests, die verschiedenen oben beschriebenen Optionen verwenden, aber durch die Veröffentlichung SO ich bin die Hoffnung, für reale Anekdoten / Daten zu kauen.

[EDIT] Klärung - jeder Tag der Operation, erstellt die Anwendung mehrere Dateien, die auf 1 Gig in der Größe von 100 MB reichen. Insgesamt könnte die Anwendung mehrere Gigs von Daten pro Tag schreiben aus.

War es hilfreich?

Lösung

könnten Sie in der Lage sein, die Dinge zu beschleunigen, sich ein wenig durch die Prüfung, wie Sie Ihre Daten während des Schreibens gepuffert wird. Dies führt dazu, sein anwendungsspezifische, wie Sie eine Vorstellung von den erwarteten Datenschreibmustern benötigen würden. Wenn die Datenkonsistenz wichtig ist, gibt es Vor- und Nachteile hier sein.

Wenn Sie nur schreiben, um neue Daten auf der Festplatte aus Ihrer Anwendung, Memory Mapped I / O wahrscheinlich nicht viel helfen. Ich sehe keinen Grund, warum Sie wollen würden Zeit in einig benutzerdefinierten codierten nativen Lösung investieren. Es scheint, wie zu viel Komplexität für Ihre Anwendung, von dem, was Sie bisher zur Verfügung gestellt haben.

Wenn Sie sicher sind Sie wirklich besser benötigen I / O-Leistung - oder nur O-Leistung in Ihrem Fall würde ich in eine Hardware-Lösung aussehen wie ein abgestimmter Disk-Array. mehr Hardware auf das Problem werfen ist oft mehr Kosten aus betriebswirtschaftlicher Sicht effektiver als Zeitsoftwareoptimierung zu verbringen. Es ist auch in der Regel schneller zu implementieren und zuverlässiger.

In der Regel gibt es viele Fallen in über Optimierung der Software. Sie werden neue Arten von Problemen zu Ihrer Anwendung einzuführen. Sie könnten in Speicherprobleme / GC Dreschen laufen, die zu mehr Wartung / Tuning führen würde. Das Schlimmste ist, dass viele dieser Probleme wird schwer sein, bevor sie in Produktion gehen zu testen.

Wenn es meine app wäre, würde ich wahrscheinlich Stick mit dem Fileoutputstream mit einiger möglicherweise abgestimmt Pufferung. Danach würde ich die altehrwürdige Lösung von mehr Hardware auf sie werfen verwenden.

Andere Tipps

Memory Mapped I / O wird Ihre Festplatten schneller laufen (!). Für linearen Zugang scheint es ein wenig sinnlos.

Ein NIO abgebildet Puffer ist die reale Sache (üblicher Vorbehalt über jede vernünftige Implementierung).

Wie bei anderen NIO direkt zugeordneten Puffer, sind die Puffer nicht normal Speicher und wird nicht GCed so effizient erhalten. Wenn Sie viele von ihnen erstellen können Sie feststellen, dass Sie aus dem Speicher / Adressraum ausgeführt werden, ohne von Java Heap ausgeführt wird. Dies ist offensichtlich eine Sorge mit langen laufenden Prozessen.

Aus meiner Erfahrung im Speicher abgebildeten Dateien ausführen viel besser als einfacher Dateizugriff sowohl in Echtzeit und Ausdauer Anwendungsfällen. Ich habe in erster Linie mit C ++ unter Windows gearbeitet, aber Linux Leistungen sind ähnlich, und Sie planen, JNI verwenden sowieso, so dass ich denke, dass es für Ihr Problem gilt.

Ein Beispiel für eine Persistenz-Engine auf Memory-Mapped-Datei erstellt, finden Sie unter Metakit . Ich habe es in einer Anwendung verwendet, wo Objekte waren einfache Ansichten über Memory-Mapped-Daten hat der Motor Pflege aller Mapping Sachen hinter den Vorhängen. Dies war sowohl schnell und speichereffiziente (zumindest im Vergleich zu herkömmlichen Ansätzen, wie sie die vorherige Version verwendet wird), und wir haben Commit / Rollback-Transaktionen kostenlos.

In einem anderen Projekt hatte ich Multicast-Netzwerk-Anwendungen zu schreiben. Die Daten wurden in randomisierter Reihenfolge senden, um die Auswirkungen von aufeinanderfolgenden Paketverlust (in Verbindung mit FEC und Blockiersystemen) zu minimieren. Außerdem gut die Daten könnten den Adressraum nicht überschreiten (Videodateien waren größer als 2 GB) so Speicherzuweisung war außer Frage. Auf der Serverseite, waren Dateiabschnitte speicherabgebildete auf die Nachfrage und die Netzwerkschicht gepflückt direkt die Daten aus diesen Ansichten; als Folge davon war der Speicherverbrauch sehr gering. Auf der Empfängerseite gab es keine Möglichkeit, die Reihenfolge, in die Pakete empfangen wurden, vorherzusagen, so hat es eine begrenzte Anzahl von aktiven Ansichten auf die Zieldatei zu erhalten, und die Daten wurden direkt in diesen Ansichten kopiert. Wenn ein Paket in einem nicht zugeordneten Bereich gebracht werden mußte, war die älteste Ansicht unmapped (und schließlich in die Datei durch das System gespült) und durch eine neue Sicht auf dem Zielbereich ersetzt. Performance waren hervorragend, vor allem, weil das System auf begehen Daten als Hintergrundaufgabe hat einen tollen Job, und Echtzeitbedingungen wurden leicht erfüllt.

Seitdem ich bin überzeugt, dass auch das beste Fein gestaltete Software-Schema nicht das Standard-I / O-Versicherung mit Memory-Mapped-Datei des Systems schlagen, weil das System weiß, mehr als Userspace-Anwendungen, wann und wie Daten sein müssen geschrieben. Auch, was ist wichtig zu wissen ist, dass die Speicher-Mapping ist ein Muss, wenn sie mit großen Daten zu tun, weil die Daten nicht zugeordnet ist (daher raubend Speicher), sondern dynamisch in den Adressraum abgebildet und durch das System der virtuellen Speichermanager geführt werden, das ist immer schneller als die Halde. Also immer das System den Speicher optimal nutzen und Daten verpflichtet, wenn sie ihn braucht, hinter dem Rücken der Anwendung, ohne sie zu beeinträchtigen.

Hoffe, es hilft.

Wie bei Punkt 3 - wenn die Maschine abstürzt und es Seiten gibt, die nicht auf die Festplatte geschrieben wurden, dann sind sie verloren. Eine andere Sache ist der Abfall des Adressraums - Abbildung einer Datei in den Speicher-Adressraum verbraucht (und erfordert zusammenhängenden Bereich), und auch auf 32-Bit-Maschinen ist es ein bisschen eingeschränkt. Aber Sie haben über 100MB sagen - so sollte es kein Problem sein. Und noch etwas -. Die Größe der Datei mmaped Erweiterung erfordert einige Arbeit

By the way, können auch Sie einige Einblicke.

ich eine Studie tat, wo ich vergleiche die Schreibleistung zu einem rohen ByteBuffer gegen die Schreibleistung auf einen MappedByteBuffer. Memory-Mapped-Dateien werden unterstützt durch das Betriebssystem und ihre Schreiblatenzen sind sehr gut, wie man in meinen Benchmark Zahlen sehen kann. Durchführen von synchronen Schreibvorgängen durch einen Filechannel ist etwa 20-mal langsamer, und das ist, warum Menschen tun asynchrone Protokollierung die ganze Zeit. In meiner Studie gebe ich auch ein Beispiel dafür, wie für ultimative Leistung sehr nahe an einem rohen ByteBuffer asynchrone Protokollierung durch eine Lock-frei und Müll freie Warteschlange zu implementieren.

Wenn Sie weniger Bytes schreiben, wird es schneller sein. Was ist, wenn Sie es durch gzipoutputstream gefiltert, oder was passiert, wenn Sie Ihre Daten in ZipFiles oder JarFiles geschrieben?

Wie oben erwähnt, verwendet NIO (auch bekannt als neue IO). Es gibt auch eine neue, neue IO herauskommt.

Die richtige Verwendung einer RAID-Festplatten-Lösung würden Ihnen helfen, aber das wäre ein Schmerz sein.

Ich mag die Idee, die Daten komprimiert werden. Gehen Sie für die gzipoutputstream dude! Das würde verdoppeln Sie Ihren Durchsatz, wenn die CPU mithalten kann. Es ist wahrscheinlich, dass Sie die Vorteile der jetzt-Standard-Doppelkern-Maschinen nehmen können, nicht wahr?

-Stosh

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top