JVM-Grundlagen für Elasticsearch: Metriken, Speicher und Monitoring

Elasticsearch ist eine Java-basierte Such- und Analytics Engine sowie Vektordatenbank, die auf Apache Lucene basiert und den Kern der Elasticsearch Platform bildet. Um Elasticsearch auf den unterstützten Plattformen auszuführen, benötigen Sie eine Java-virtuelle Maschine (JVM). Die JVM bietet eine Platform-unabhängige Laufzeitumgebung, und Sie können Elasticsearch in einer virtuellen Umgebung auf dem vorhandenen Betriebssystem ausführen. Die JVM abstrahiert das zugrundeliegende Betriebssystem und die Hardware, sodass Java-Anwendungen auf jeder Platform ausgeführt werden können.
Das Verständnis der Speicherverwaltung der JVM und der Objektbereinigung mittels Garbage Collection (GC) ist der Schlüssel zur Fehlersuche bei Problemen wie java.lang.OutOfMemoryError (Exit-Code 127). Diese Probleme treten auf, wenn die JVM keinen Speicher mehr ausführt oder ein Exit-Code 137 vorliegt, was in der Regel darauf hinweist, dass der Out-of-Memory (OOM) Killer des Hosts den JVM-Prozess aufgrund übermäßiger Speichernutzung beendet hat. Dieser Blog zeigt Ihnen, wie Sie die Muster der Speichernutzung untersuchen und diese JVM-Probleme beheben können.
Ich werde auch die Rolle der JVM erläutern und wie diese mithilfe bestehender Elasticsearch-APIs korreliert werden kann. Dies liefert wertvolle Einblicke in den Zustand der Elasticsearch-JVM und hilft Ihnen bei der Entscheidung, ob Sie diese weiter an Ihren eigenen Anwendungsfall anpassen möchten.
Wie in der Elasticsearch JVM-Dokumentation erwähnt, funktionieren die Standardwerte der JVM-Optionen, die mit dem Produkt versendet werden, effizient in allen unterstützten Produktionsumgebungen; diese Standardwerte können die meisten Anwendungsfälle für Such- und Indexierungsvorgänge abdecken. Es wird nicht empfohlen, Werte zu ändern oder benutzerdefinierte Werte für die JVM-Optionen oder -Einstellungen hinzuzufügen.
Wenn Sie der Meinung sind, dass Änderungen für Ihre Workload vorteilhaft wären, kontaktieren Sie bitte den Elastic Support, bevor Sie diese vornehmen.
Was ist eine JVM?
Eine Java virtuelle Maschine ist ein integraler Bestandteil der Java Runtime Environment (JRE), die im Java Development Kit (JDK) enthalten ist.

Die JVM ähnelt einem Computerprogramm, das beim Ausführen von Java-Anwendungen hilft. Sie existiert nicht als physische Maschine, fungiert aber wie eine, indem sie Java-Code in Anweisungen übersetzt, die Ihr unterstütztes Betriebssystem verstehen kann. Die JVM kümmert sich zudem um wichtige Aufgaben wie Speicherverwaltung, die Handhabung der Garbage Collection und die Sicherheit Ihrer Anwendungen.
Als Nächstes konzentrieren wir uns auf die JVM-Speicherverwaltung und die Garbage Collection – ein wichtiger Punkt in Elasticsearch, den wir bei der Fehlerbehebung von Problemen mit der Speicherleistung oder OOM-bezogenen Problemen häufig überprüfen.
Um die Speicherverwaltung und Garbage Collection zu verstehen, müssen Sie zunächst die logische Darstellung des Heap-Bereichs (oder Heap-Speichers) verstehen, in dem sich alle Objekte befinden, wenn eine JVM startet.
Verständnis des JVM-Heap-Speichers: Young und Old Generation
Ein Heap-Bereich, oder Heap-Speicher, ist eine Kombination aus Speicherpools, in denen die Objekte basierend auf ihrem Lebenszyklus und Alter gespeichert werden. Ein JVM-Heap-Speicher besteht hauptsächlich aus einer „Young Generation“ und einer „Old Generation“. Die „Young Generation“ ist, wie unten dargestellt, weiter in Eden- und Survivor-Regionen unterteilt. Die Java-Objekte werden in diesen Bereichen basierend auf ihrem Alter und ihrer Referenz zugewiesen und anschließend von den „Young“- in die „Old“-Regionen verschoben.
Der Großteil der Heap-Auslastung im Eden-Space wird schnell bereinigt. Nicht freigegebener Heap wird in einen der Survivor-Spaces (S0 oder S1) verschoben, wo er üblicherweise nach einem exponentiellen Zerfallsmuster bereinigt wird. Wenn er darüber hinaus bestehen bleibt, wird er in den Tenured-Space verschoben.
Gesamter JVM-Heap-Speicher = Young generation (Eden- und Survivor-Bereiche S0 und S1) + Old generation (Tenured)

Flächendiagramm/Region der Young Generation
Wenn eine Java-Anwendung startet, erstellt sie neue Objekte und weist diese dem Flächendiagramm zu, das als Heap-Speicher bezeichnet wird. Der Eden-Bereich der Young Generation ist der erste Ort, an dem die Anwendung neu erstellte Objekte zuweist. Dieses Flächendiagramm ist für die Zuweisung neuer Objekte reserviert. Wenn es voll ist, werden die berechtigten Objekte entweder bereinigt (Garbage Collection) oder in andere Regionen verschoben.
Wenn eine kleine Garbage Collection stattfindet, werden die referenzierten Objekte in einen anderen Unterabschnitt verschoben, den Survivor-Bereich S0. Die nicht referenzierten Objekte werden gelöscht, um den Speicherplatz in Eden freizugeben. Dieser Bereich enthält die Objekte, die den Garbage-Collection-Prozess überlebt haben, daher der Name Survivor-Bereich.
Der gleiche Zyklus wiederholt sich, wenn der Eden-Space wieder voll ist. Diesmal werden die Objekte, die sowohl Eden als auch S0 überlebt haben, in die S1-Region verschoben, und dieser Prozess setzt sich fort.
Die Objekte, die die Garbage Collections in Eden, S0 und S1 überlebt haben, werden basierend auf dem Altersrechner in die Old Generation befördert.
Flächendiagramm/Region der Old Generation
Die Old Generation (auch als Tenured Generation bekannt) ist eine Sammlung langlebiger Objekte, die mehrere Garbage-Collection-Ereignisse in der Young Generation (Minor GCs) überlebt haben. Objekte, die eine bestimmte Anzahl von Zyklen im Survivor-Space überlebt haben, werden vom Algorithmus in die Old Generation verschoben, was auch als Objekt-Promotion bezeichnet wird.

Das obige sägezahnartige GC-Muster aus der Stack-Überwachung zeigt, dass der JVM-Heap-Speicher während der Minor-Garbage-Collection reduziert wird, da der GC die unerwünschten Objekte aus dem Speicher entfernt. Nach einigen Zyklen sammeln sich Objekte an und der GC wird erneut aktiv, um die Objekte zu bereinigen.
Garbage-Collection-Methode
Elasticsearch wird mit einer unterstützten gebündelten JDK-Version ausgeliefert; die Details sind in den Versionshinweisen dokumentiert. Bis v6.4 verwendete Elasticsearch den Concurrent Mark Sweep (CMS) Garbage Collector, der in JDK9 als veraltet markiert wurde. Elasticsearch verwendet jetzt den Garbage-First (G1) Garbage Collector als Standard-GC-Methode. Er bietet zudem eine bessere Leistung im Vergleich zur CMS-GC-Methode. Der interne Mechanismus von G1GC ist komplex und umfasst viele Phasen, aber lassen Sie uns die Grundlagen erläutern.
Um G1GC zu verwenden, nutzen Sie das JVM-Flag -XX:+UseG1GC in der Elasticsearch JVM-Option. Bei G1GC wird das gesamte Heap-Flächendiagramm in gleich große Regionen unterteilt -XX:G1HeapRegionSize=1m, die je nach Heap-Größe zwischen 1 MB und 32 MB variieren können. Die Eden-, Survivor- und Old-Generationen sind logische Mengen dieser Regionen und nicht zusammenhängend. Abgesehen davon gibt es innerhalb des Heap-Flächendiagramms eine Humongous-Region sowie einen freien/verfügbaren Bereich. Die Humongous-Region wird verwendet, um Objekte zuzuweisen, die mehr als die Hälfte der Regionsgröße einnehmen.

Der G1GC hat ein Ziel für die Pausenzeit (-XX:MaxGCPauseMillis=200), das er während der Garbage Collection einzuhalten versucht. Das bedeutet, dass er während der Garbage Collection sicherstellt, dass die JVM keine längere Pause als diesen Wert erfährt, was ihn besser macht als CMS oder andere Collector, bei denen dies keine Option ist. Insgesamt wird empfohlen, die GC-Einstellungen auf den Standardwerten zu belassen, wodurch die GC-Pause für eine verbesserte Leistung innerhalb der Grenzwerte gehalten wird.
Elasticsearch-APIs für den JVM-Status
Jede Aufgabe, die Elasticsearch ausführen möchte, muss die JVM bitten, etwas Arbeitsspeicher zuzuweisen, um sie ausführen zu können. Wie oben erwähnt, übernimmt die JVM die Speicherverwaltung für Elasticsearch, sodass sich Elasticsearch nicht darum kümmern muss. Administratoren könnten jedoch daran interessiert sein, den JVM-Status über die Elasticsearch-APIs zu überprüfen, um sicherzustellen, dass alles wie erwartet verläuft.
Um alle Einstellungen zu überprüfen, die für die Elasticsearch-JVM angegeben oder als Eingangsargumente bereitgestellt wurden, verwenden Sie die Node-Info-API mit dem JVM-Attribut (auch beschrieben in der Dokumentation).
GET _nodes/_all/jvm Diese API liefert Details zur Node-Konfiguration, einschließlich JVM-Eingangsargumenten, Speicherpools und Heap-Größe.
Wenn Sie zusätzlich die Metriken der Elasticsearch-JVM für die Uptime eines bestimmten Node, den in allen Speicherpools verwendeten Heap oder Statistiken zur Garbage Collection überprüfen möchten, können Sie die Node-Statistik -API verwenden. Sie liefert detaillierte Metriken zu jedem der genannten Punkte.
GET _nodes/stats/jvm
or
GET _nodes/stats/jvm?filter_path=nodes.*.jvmHinweis: Elasticsearch empfiehlt nicht, Entscheidungen auf Basis des heap_percent-Werts zu treffen, der über die nodes stats API abgerufen wird. Unsere Benutzeroberfläche berechnet den Speicherdruck, und der Nutzer sollte die notwendigen Maßnahmen basierend auf der in diesem Blog beschriebenen Berechnung ergreifen.
Überprüfung von JVM-Metriken mit dem integrierten JDK-Tool
Wenn Sie ein fortgeschrittener Nutzer sind und Echtzeitstatistiken zu einer laufenden JVM ohne die Verwendung von Elasticsearch-APIs abrufen möchten, können Sie das mitgelieferte Java verwenden und jstat ausführen, um die Live-Statistiken zu überprüfen. Suchen Sie hierzu zunächst das Java-Home-Verzeichnis oder das bin-Verzeichnis sowie die PID des Elasticsearch-Prozesses. Verwenden Sie aus dem bin-Verzeichnis das Tool jstat:
./jstat -gcutil <PID> 2000Hierbei ist 2000 das Intervall in Millisekunden, nach dem die Statistiken abgerufen und auf der CLI ausgegeben werden. Dieser Befehl ist hilfreich, um zu ermitteln, wie häufig die GC in allen Bereichen stattfindet und wie schnell Speicherpools durch Objekte gefüllt werden (Raten für Objekterstellung und -promotion).
Dies ist keine Alternative zu den oben genannten APIs, sondern dient eher dem Debugging auf Entwicklerebene.
Das war’s!
In diesem Blogbeitrag haben wir die grundlegenden Konzepte von Java virtuelle Maschinen, verschiedene Speicherpools, die Bedeutung der Garbage Collection und die Überprüfung der JVM-Statistiken von Elasticsearch behandelt. Im nächsten Blogbeitrag besprechen wir die wichtigen JVM-Einstellungen und wie Sie deren aktuelle Metriken in Elasticsearch abrufen können.
Sollten Sie Fragen haben oder weiteren Support benötigen, zögern Sie bitte nicht, uns zu kontaktieren. Wir sind jederzeit für Sie da und helfen Ihnen gern!
Die Entscheidung über die Veröffentlichung der in diesem Blogeintrag beschriebenen Leistungsmerkmale und Features sowie deren Zeitpunkt liegt allein bei Elastic. Es ist möglich, dass noch nicht verfügbare Leistungsmerkmale oder Features nicht rechtzeitig oder überhaupt nicht veröffentlicht werden.