5 Tipps, wie Sie häufige Java-Performance-Probleme mit Monitoring-Tools vermeiden
Java ist eine der am weitesten verbreiteten Programmiersprachen und wird häufig von Backend-Entwicklern als serverseitige Sprache verwendet. Spotify, Twitter oder Signal sind nur einige bekannte Beispiele für Anwendungen, die Java verwenden. Java hat sich im Laufe der Jahre enorm weiterentwickelt und lässt sich nicht nur einfach schreiben, kompilieren und debuggen, sondern ist – verglichen mit anderen Programmiersprachen – auch sicherer, portabler und effektiver in der Speicherverwaltung.
Allerdings kann es auch bei Java zu Performance-Problemen kommen. Diese hängen meist mit dem Speicher, gleichzeitigen Zugriffen (Concurrency) oder dem Code selbst zusammen. Mit einem Application-Monitoring-Tool, das auch für Java geeignet ist, lassen sie sich jedoch meist leicht vermeiden oder beheben.
Wir haben 5 häufige Java-Performance-Probleme für Sie zusammengestellt und geben Tipps, wie Sie diese mit einem guten Java-Monitoring-Tool wie Applications Manager von ManageEngine einfach vermeiden können.
Warum ist ein Java-Monitoring so wichtig?
Wie bei jeder anderen Anwendung auch können sich Performance-Probleme bei Java mitunter auf das gesamte Unternehmen und dessen Einnahmen auswirken. Gerade bei E-Commerce-Websites lässt sich bereits bei Latenzzeiten (Latency) von 100 Millisekunden ein Umsatzrückgang feststellen, wie beispielsweise Amazon bereits 2012 feststellen musste.
An dieser Stelle kommt das Java-Performance-Monitoring ins Spiel: Eine für Java geeignete Applications-Monitoring-Lösung analysiert das Verhalten der Java-Anwendung, benachrichtigt bei Anomalien sofort IT-Administratoren oder Entwickler und erstellt regelmäßig Berichte über die Anwendungs-Performance. Mit einem robusten Java-Performance-Monitoring-Tool wie Applications Manager von ManageEngine lassen sich so eine hohe Performance erzielen, kostspielige Fehler vermeiden und ein optimales Nutzererlebnis bieten.
1. Speicherlecks (Memory Leaks) und ungenügender Speicherplatz („Out of Memory“-Fehler)
Ein „Out of Memory"-Fehler tritt auf, wenn Sie versuchen, Daten zum Speicher hinzuzufügen, aber nicht genug Platz dafür vorhanden ist. Jeder Java-Variable wird eine bestimmte Speichergröße zugewiesen. Soll eine Variable nicht mehr verwendet werden, muss dieser Speicher freigegeben werden, um sogenannte Speicherlecks (Memory Leaks) zu vermeiden. Tritt dies in einem häufig ausgeführten Code auf, kann es dazu kommen, dass die Java Virtual Machine (JVM) ihren gesamten Speicher ausschöpft. Dies führt dann zum gefürchteten „Out of Memory"-Fehler.
Auswirkungen: 9/10
So lösen Sie Probleme mit Memory Leaks sowie „Out of Memory“-Fehler:
Um Memory Leaks und “Out of Memory”-Fehler zu beheben, sollten Sie sich zunächst detailliertere Informationen zu verschiedenen Speicherattributen wie Heap-, Non-Heap- und Swap-Speicher anzeigen lassen. Am einfachsten funktioniert das mit einem Java-Monitoring-Tool wie Applications Manager. Durch die Überwachung von Java-Kennzahlen wie den drei genannten können Sie sehr schnell sehen, was den meisten Platz im Speicher einnimmt. Idealerweise sollten Sie zudem Schwellenwerte für diese Attribute festlegen, bei deren Überschreitung Sie sofort benachrichtigt werden.
Was bedeuten die Begriffe „Heap Memory“, „Non-Heap Memory“ und „Swap Memory”?
Der „Heap Space“ wird in Java genutzt, um Java-Objekten während der Laufzeit einen dynamischen Speicher zuzuweisen. Im Heap-Speicher werden neue Objekte erzeugt und Verweise auf diese Objekte im Stapelspeicher (Stack Memory) gespeichert. Der restliche Speicher, der von der JVM für andere Zwecke verwendet wird, wird als „Non-Heap Memory“ bezeichnet.
Der Swap-Speicher ist ein Teil des virtuellen Speichers auf der Festplatte, der zum Einsatz kommt, wenn der Arbeitsspeicher voll ist.
Übrigens:
Applications Manager bietet zahlreiche vorkonfigurierte Monitore (=Sets mit Monitoring-Einstellungen) für Server und Anwendungen – unter anderem auch für Java Runtime. Sofern Sie bereits einen Java Runtime Monitor angelegt haben, finden Sie darin detaillierte Informationen zum Heap-, Non-Heap- und Swap-Speicher. Wählen Sie dazu unter Monitore / Java Runtime ggf. die Java-Umgebung aus, zu der Sie detaillierte Informationen erhalten möchten. Aktuelle Auswertungen zu Heap Memory, Non-Heap Memory und Swap Memory (im Widget „Host Memory“) finden Sie auf dem Reiter „Overview“. Um beispielsweise einen Alarm für den Heap-Speicher zu konfigurieren, klicken Sie bitte auf „Configure Alarms“ (rechts unter dem jeweiligen Widget).
2. Deadlocks bei Threads
Java-Anwendungen sind meist Multithreading-fähig. Wenn zwei oder mehr Threads versuchen, gleichzeitig auf dieselben Ressourcen zuzugreifen, wird der Datenpool gesperrt, damit jeder Thread exklusiven Zugriff auf die gemeinsamen JVM-Ressourcen erhält. Ein Deadlock entsteht, wenn ein Thread Ressourcen sperrt, während andere Threads darauf warten, dass die Sperre aufgehoben wird. Deadlocks führen dazu, dass die Anwendung langsamer wird oder sogar abstürzt.
Auswirkungen: 10/10
So vermeiden Sie durch Deadlocks verursachte Probleme in Java:
Ein gutes Java-Performance-Monitoring-Tool hilft Ihnen dabei, durch Deadlocks verursachte Probleme zu vermeiden, indem es Threads überwacht. Auf diese Weise können Sie Deadlocks einfach identifizieren und sogar die genaue Code-Zeile ermitteln, die eine Sperrung verursacht hat. Dadurch können Sie die Sperre einfach aufheben und das Problem lösen.
Übrigens:
Eine detaillierte Statistik zu Threads in Ihrer JVM finden Sie im Java Runtime Monitor (Monitore / Java Runtime) von Applications Manager auf dem Reiter „Threads”.
3. Garbage Collection
Der Garbage Collector in Java entfernt nicht mehr benötigte Daten, um Speicherplatz für neue Objekte zu schaffen. Manchmal werden bei der Speicherbereinigung alle Threads angehalten, die versuchen, auf Ressourcen der Java Virtual Machine (JVM) zuzugreifen, um Speicherplatz zurückzugewinnen. Allerdings kann der Garbage Collector die Leistung von Java beeinträchtigen, wenn er zu häufig durchgeführt wird. Auch ein „voller“ Garbage Collector kann zu einer Verlangsamung der Anwendung führen. Um eine optimale Leistung zu erzielen, sollte die Speicherbereinigung daher nur einen kleinen Prozentsatz der CPU-Zeit beanspruchen (weniger als zehn Prozent). Beträgt die CPU-Auslastung durch den Garbage Collector mehr als 20 Prozent, führt das in der Regel zu Performance-Problemen der Anwendung im Zusammenhang mit dem Speicher.
Auswirkungen: 8/10
So vermeiden Sie Probleme mit dem Garbage Collector:
Da eine übermäßige Nutzung der Speicherbereinigung die CPU belasten und damit die Prozesse der JVM unterbrechen kann, sollten Sie den Garbage Collector beim Java-Performance-Monitoring mit im Auge behalten. Gute Monitoring-Lösungen bieten Ihnen dazu unter anderem die Möglichkeit, Schwellenwerte für den Heap-Speicher festzulegen, damit Sie bei eventuellen Performance-Problemen sofort benachrichtigt werden. Mit dem Java Monitor, der im APM Add-on von Applications Manager enthalten ist, können Sie zudem auch die CPU-Auslastung, die Antwortzeit, die Garbage-Collection-Zeit und andere Kennzahlen überwachen, um negative Auswirkungen auf die Java-Performance zu vermeiden.
Tipp:
Im Java Runtime Monitor (unter Monitore / Java Runtime) von Applications Manager finden Sie auf dem Reiter „Garbage Collection“ wichtige Kennzahlen zur Speicherbereinigung wie die dafür verwendete Zeit pro Minute oder in Prozent sowie die Anzahl der Bereinigungen pro Minute.
Der Java Monitor, den Sie auf dem Reiter „APM“ für eine Java-Anwendung aufrufen können, enthält (unter JVM / Garbage Collector) detaillierte Informationen zur Anzahl der bereinigten Objekte und der dazu benötigten Zeit (siehe Screenshot).
4. Probleme auf Code-Ebene
Theoretisch sollten alle Probleme auf Code-Ebene vor der Einführung einer Anwendung erkannt und behoben werden. In der Praxis ist das aber leider nicht immer der Fall. Probleme auf Code-Ebene sind einer der Hauptfaktoren, die zu Performance-Engpässen führen. Diese entstehen durch Fehler (Bugs) in den Code-Konstruktionen, wie mangelhafte Iterationen, die unsachgemäße Verwendung generischer Vorlagen, ineffizienter Code, der zu zeitlichen Problemen führt, die Unfähigkeit, große Serverlasten zu bewältigen, eine schlechte Wahl der Datenstruktur sowie nicht durchgeführte oder ungeeignete Unit-Tests.
Die Folgen eines Bugs können unter anderem redundante und irreführende Ausgaben sein. Ein Fehler kann auch dazu führen, dass ein System den Überblick über seine Transaktionen verliert, eine falsche Transaktion durchführt oder sich sogar weigert, eine Transaktion zu bearbeiten. Auch eine beschädigte Datenbank oder der komplette Ausfall des Systems sind weitere mögliche Folgen eines Bugs. Außerdem lassen sich einige Fehler nicht so leicht beheben, wodurch viel Entwicklungszeit verschwendet werden kann.
Das häufigste Symptom von Fehlern auf Code-Ebene sind allerdings Loops, die CPU-Zyklen innerhalb der JVM verbrauchen und so die Anwendungs-Performance beeinträchtigen. Vor diesem Hintergrund sollten Entwickler diese Probleme lösen, bevor das fertige Produkt auf den Markt kommt.
Auswirkungen: 9/10
So lassen sich Probleme auf Code-Ebene vermeiden:
Probleme auf Code-Ebene lassen sich bis zu einem gewissen Grad vermeiden, wenn während der Entwicklung der Anwendung bewährte Verfahren eingesetzt werden. Probleme, die erst nach der Entwicklung auftreten, können mit Lösungen zum Applications-Performance-Monitoring (APM) isoliert werden. Das Add-on „APM Insight“ von Applications Manager unterstützt Sie dabei, Probleme auf Code-Ebene in Java-Anwendungen in Entwicklungs-, QA- und Produktiv-Umgebungen zu isolieren.
5. Pool-Verbindungen
Da es teuer ist, für jede Datenabfrage eine neue Verbindung aufzubauen, werden für die Datenübertragungen in der Regel bestehende Pool-Verbindungen verwendet. Wenn die Anzahl der Verbindungen allerdings die Höchstgrenze erreicht, werden neu eingehende Anfragen so lange zurückgestellt, bis die bestehenden Datenbankanfragen abgeschlossen sind. Wenn eine Verbindung aus einem bestimmten Pool abgeleitet und später nicht wieder für den Pool freigegeben wird, kommt es zu Verbindungsabbrüchen (Connection Leaks), die zu Anwendungsfehlern führen können.
Auswirkung: 8/10
So vermeiden Sie Probleme mit Pool Connections:
Um Anwendungsfehler in Folge von Connection Leaks zu vermeiden, sollten Sie wichtige Pool-Kennzahlen („allocated“, „free“ und „managed“) überwachen. Darüber hinaus sollten Sie auch Java-Performance-Kennzahlen in Bezug auf andere Verbindungen zur Datenbank im Auge behalten, wie beispielsweise die Gesamtverbindungszeit, die aktiven Verbindungen und den Zustand des Datenbankservers. Die gewonnenen Informationen können Ihnen helfen, herauszufinden, warum Verbindungen abgebrochen wurden. Ursache könnte beispielsweise eine Fehlprogrammierung sein, durch die Datenbankzugriffe nicht geschlossen werden und somit dauerhaft blockiert bleiben. Es könnte sich auch um eine Fehlkonfiguration seitens der Datenbank oder der Bibliothek zum Pool-Management handeln. Oder es wurde ein Bug gefunden, der bei bestimmten Ereignissen eintrifft, und die Abbrüche daher hervorgerufen werden.
Der Java Runtime Monitor von Applications Manager überwacht unter anderem die Verfügbarkeit, Antwort- und Verbindungszeiten von Java sowie viele weitere Parameter. Das Widget „Connection Time“ zeigt Ihnen an, wie schnell eine Verbindung zur JVM aufgebaut werden konnte und gibt Ihnen Hinweise auf mögliche Probleme in der JVM, am Server etc.
Java-Performance-Monitoring mit Applications Manager
Die Anwendungs-Performance-Monitoring-Lösung Applications Manager von ManageEngine unterstützt IT-Administratoren mit zahlreichen Funktionen zur Überwachung von Java-Anwendungen dabei, die oben beschriebenen gängigen Java-Performance-Probleme zu vermeiden. Darüber hinaus lassen sich mit der Lösung unterschiedlichste Business-Anwendungen in physischen, virtuellen oder Cloud-basierten IT-Infrastrukturen proaktiv überwachen. Zahlreiche Unternehmen weltweit setzen beim Performance-Monitoring ihrer Java-Anwendungen bereits auf die ManageEngine-Lösung.