Wie halten Sie 5 GB Speicher konstant in der Anwendung, ohne dass die Performance durch GC beeinträchtigt wird?

9

Meine App ist eine Geo-Anwendung. Aufgrund einer kurzen Reaktionszeit lädt jede Instanz alle Punkte in den Speicher und speichert sie in einer Struktur (Quad-Tree).

Jede Minute laden wir alle Punkte (um mit der db synchronisiert zu werden) und setzen sie in wenige Quad-Bäume.

Wir haben jetzt 0,5 GB Punkte. Ich versuche mich auf das nächste Level von 5GB Punkten vorzubereiten. JVM: -XX: NewSize = 6g -Xms20g -Xmx20g -XX: + Verwenden Sie ConcMarkSweepGC -verboseGC -XX: + PrintGCTimeStamps -XX: + PrintGCDateStamps -XX: + PrintGCDetails

Start der Instanz dauerte viele Male wegen GC in der App zusätzlich die GC leiden die ganze Zeit.

Ich hätte gern einen Verweis auf GC mit großem Heap.

Ich kann mir dafür einige Lösungen vorstellen:

  1. Um nur die Änderungen in der Datenbank zu aktualisieren und nicht alle db jedes Mal zu laden. Nachteile - leidet immer noch an GC während der frühen Phase der Anwendung, Langzeit-GC.

  2. Off-Heap-Lösung. Speichern Sie im Quadbaum den Punkt ids und speichern Sie die Punkte aus dem Heap. Nachteile - Serialisierungszeit, die Geostruktur ist ein Komplex von wenigen Objekten und nicht einfaches Objekt.

  3. Erstellen Sie für jede Instanz eine zusätzliche Instanz mit der Struktur und Abfrage für diese Instanz. Die Geo-Instanz enthält ein langlebiges Objekt und kann GC-Anpassungen für langlebige Objekte vornehmen. Nachteile - Komplexität und Reaktionszeit.

Alle Verweise auf Artikel über Apps, die wenige langlebige Objekte enthalten, sind mehr als willkommen.

Läuft auf Ubuntu (Amazon). Java 7. Dosnt hat Speicherbeschränkung.

Das Problem ist lange Pausenzeit jedes Mal, wenn wir die Daten aktualisieren.

Gc Protokoll für die Aktualisierung:

%Vor%     
Avihai Marchiano 06.06.2014, 08:43
quelle

3 Antworten

0

Ich habe versucht, die JVM-Wiedergabe mit der neuen Größe, der Heap-Größe ... zu optimieren. Auch versuchte G1 (-XX: MaxGCPauseMillis = 200) ohne Erfolg und bekam ziemlich bald OOM.

Schließlich war die Lösung, nur Änderungen zu laden. Wenn nur die Last geändert wird, betrug die Pausenzeit des GC nur 0,55% und die durchschnittliche Pausenzeit 17,3 ms.

Wenn alle Daten geladen werden, haben Sie keine gleichzeitigen Probleme, da Sie die Serving-Klassenstrukturen (Quad, Maps) während der Aktualisierung nicht sperren müssen, da Sie eine neue Serving-Klasse erstellen und sobald die neue Serving-Klasse bereit ist Serve aktualisieren Sie die Referenz der Serving-Klasse mit der aktualisierten Klasse. Um das Sperren der Serving-Daten zu vermeiden, erstellen wir eine neue Serving-Klasse basierend auf den alten Daten und führen die aktualisierten Daten mit ihr zusammen, so dass 99,9% der Daten, die zuvor geladen wurden und in der alten Generation existieren, nicht benötigt werden reinigen . Der GC wird nur die Quad-Bäume Referenzen und die Kartenschlüssel Referenzen reinigen und es wird von CMS gereinigt werden.

Wenn Sie Ihre Daten vollständig aktualisieren müssen, tun Sie es nicht gleichzeitig. Versuchen Sie, Ihre Daten in wenige Strukturen zu zerlegen und hin und wieder jede Datenstruktur zu aktualisieren. In diesem Fall leidet der GC unter viel weniger Pausen und teuren Fehlern.

Wenn Sie es auf einmal tun müssen und Sie sich lange Pausen leisten können, als eine kleine Nachricht zu erstellen, wird das Objekt an das alte Gen übergeben.

In unserem Test gibt es eine konstante Last von 6 Thread und alle 3 Minuten laden wir 3.5G Serving-Daten und ersetzen die alte. Ein Test, der gemacht wurde mit: -XX: Neue Größe = 6g -Xms20g -Xmx20g -XX: + UseConcMarkSweepGC

Ausbeute:

GC trat seltener auf (Mittleres Intervall zwischen den Sammlungen (ms) 3735), aber die meisten dauern etwa 4 Sekunden.

Bei Änderung zu: -XX: CMSInitiatingOccupancyFraction = 70 -Xms20g -Xmx20g -XX: + UseConcMarkSweepGC

Ausbeute:

    
Avihai Marchiano 17.06.2014, 05:38
quelle
2

Die Leute haben einige sehr gute Kommentare zu Design-Punkten gemacht, die Sie unbedingt beachten sollten. Wenn Sie GC-Implikationen berücksichtigen, ist nur Ihre Frage ein wenig schwierig zu beantworten, da das Garbage Collection-Tuning keine exakte Wissenschaft ist. Was Sie in Betracht ziehen sollten, ist der tatsächliche GC-Algorithmus, den Sie verwenden. Aber zuerst ein kleiner Hintergrund:

Die Garbage-Collection ist generationsübergreifend und ihre Leistung beruht auf dem hohe Kindersterblichkeit Rate von Objekten - das heißt, Objekte werden während des Anwendungsflusses erstellt und schnell zerstört. Sie halten sich an großen Objekten fest (aufgrund der Caching-Natur), das heißt, Sie werden Eden auffüllen und GC wird aufgefordert, diese Objekte zu Überlebenden und feststehenden Räumen zu fördern.

Dies würde bedeuten, dass, wenn Sie jemals diesen Speicher zurückfordern müssen, er wahrscheinlich in der Tenure ist und daher eine längere GC-Pausenzeit zum Sammeln benötigt. Angesichts der Größe Ihres Heapspeichers ist dies jedoch möglicherweise kein Problem, da möglicherweise nie ein vollständiger GC durchgeführt werden muss. Eine gesunde Anwendung wird oft für sehr kurze Zeit erwartet, um Eden zu sammeln, also lasst euch nicht von dem Garbage Collector ablenken. Allerdings macht euch ein Full GC Sorgen. Wenn Sie keine Garbage-Collector-Protokolle haben, die jetzt aktiviert sind, ist es an der Zeit, dies zu tun, da Sie dann messen und keine Annahmen treffen können, wenn Sie es bereits sind.

%Vor%

Siehe auch Antwort für weitere Details.

Ab Java 7 Update 4 können Sie den G1 Garbage Collector verwenden. Dieser Algorithmus wurde speziell für das Arbeiten mit großen Heaps auf Multicore-Rechnern entwickelt. Wenn Sie Ihre Anwendung starten, würden Sie etwas wie diesen Befehl verwenden:

%Vor%

Damit können Sie die Größe des Heapspeichers und eine Zielleistung angeben, die Sie erreichen möchten. G1 funktioniert etwas anders als der standardmäßig verwendete Markierungs- und Sweep-Algorithmus, da es den Heap in verschiedenen Regionen betrachtet und versucht, Bereiche zu ermitteln, in denen sich meistens Müll befindet. Vollständig wiederherstellbare Segmente des Heaps sind billig zu reklamieren und finden so viele von diesen als möglich und sammle sie innerhalb deiner gewünschten Pausenzeit. Es macht so viel wie möglich parallel dazu, Ihre Multicores zu nutzen, um Zeitverschwendung beim Stoppen der Welt zu vermeiden.

Es ist sicherlich nicht garantiert, dass G1 die Silberkugel für Ihr Problem sein wird, aber mit Ihren Eigenschaften, die Sie finden, funktioniert es wirklich gut für Sie (Dinge, die nicht im Cache benötigt werden, können einfacher entfernt werden und sind wahrscheinlich nahe am Ortsprinzip). Es gibt einige Anfängerinformationen zu G1 hier . Werfen Sie auch einen Blick auf diesen Artikel , der viel mehr bietet Tiefe, die ich hier habe.

    
Jim 09.06.2014 00:17
quelle
1

Ich weiß, dass dies eine alte Frage ist, aber ich dachte, es wäre richtig, wenn Ihre Anwendung viel Zwischenspeicherung verwendet, können Sie von einer größeren jungen Generation profitieren. Aus irgendeinem Grund wird dies selten empfohlen, aber ich habe einige wirklich gute Ergebnisse in einem Caching-Anwendungsfall gehabt. Der beste Ort für Objekte zum Sterben ist in der jungen Generation. Es gibt grundsätzlich keine Kosten für das Sammeln von Objekten in jungen Jahren. Das Schlimmste, was passieren kann, ist, dass Sie Objekte haben, die gerade lang genug leben, um sich in den gesicherten Raum zu bewegen, und dann sofort sterben.

Im Hotspot gibt es zwei Möglichkeiten.

  1. Erhöhen Sie die Tenuring-Schwelle: Dies ist die Anzahl der kleineren GC-Zyklen, bevor ein Objekt gefördert wird, was diesen Objekten mehr Zeit zum Sterben in der jungen Generation gibt
  2. erhöhen Sie die Größe der jungen Generation. Geringfügige Sammlungen werden weniger häufig stattfinden, und daher ist mehr Zeit für Objekte, in der jungen Generation zu sterben.

Wenn Sie viel Speicher zum Spielen haben, würde ich versuchen, der jungen Generation einen sehr großen Betrag zuzuweisen. Versuchen Sie, der jungen Generation mindestens zweimal das zu geben, was Sie zu Lebzeiten im Cache erwarten können. Belassen Sie die Tenuring-Schwelle zunächst bei 2.

Mit einem solchen Setup haben wir seit über einem Monat einen Cache-Server (Infinispan) ohne größere Sammlungen betrieben. Kleinere Sammlungen laufen ungefähr jede Stunde und höchstens 0,2 Sekunden Pause ab, um 6-7 GB Müll zu sammeln. Das Live-Set ist zu jeder Zeit ungefähr 1 GB groß. Es ist dieses Live-Set, das in erster Linie die Zeit bestimmt, die es braucht, damit die junge Generation die Anzahl der Sammlungen weiter erhöhen kann, aber die Pausenzeiten nicht viel ändern sollte.

In einer Anwendung, die neben dem Zwischenspeichern andere Dinge erledigt, funktioniert dies möglicherweise nicht perfekt. In meinem Fall hält sich der feste Speicherplatz bei etwa 120MB. Idealerweise haben Sie genug Platz für Ihre langlebigen Objekte und müssen nur einmal auf Tenured verschieben. Je nach Anwendung kann dies schwierig sein.

    
JimmyJames 11.03.2016 14:44
quelle