Lösung für die hohe CPU-Auslastung des Tomcat-Prozesses

Lösung für die hohe CPU-Auslastung des Tomcat-Prozesses

Die CPU stellt häufig einen Engpass bei der Systemleistung dar. Dies kann folgende Ursachen haben:

  • Speicherlecks führen zu häufigem GC, was wiederum eine hohe CPU-Auslastung verursacht
  • Der Codefehler erstellt eine große Anzahl von Threads, was zu häufigen CPU-Kontextwechseln führt.

Wenn wir sagen, dass die CPU-Auslastung zu hoch ist, impliziert dies einen Benchmark-Wert zum Vergleich, wie zum Beispiel

  • Durchschnittliche CPU-Auslastung der JVM bei Spitzenlast 40 %
  • Eine CPU-Auslastung von 80 % wird als abnormal angesehen

Ein JVM-Prozess besteht aus mehreren Java-Threads:

  • Einige warten auf Arbeit
  • Andere sind auf Mission

Das Wichtigste ist, herauszufinden, welche Threads CPU-Auslastung haben, und den Problemcode über den Thread-Stapel zu lokalisieren. Wenn Sie nicht feststellen, dass die CPU-Auslastung einzelner Threads besonders hoch ist, überlegen Sie, ob der Thread-Kontextwechsel die hohe CPU-Auslastung verursacht.

Fall

Programm simuliert hohe CPU-Auslastung - erstellt 4096 Threads im Thread-Pool

Starten Sie das Programm in der Linux-Umgebung:

java -Xss256k -jar demo-0.0.1-SNAPSHOT.jar

Die Thread-Stack-Größe ist mit 256 KB angegeben. Für das Testprogramm ist der Standardwert des Betriebssystems von 8192 KB zu groß, da 4096 Threads erstellt werden müssen.

Mit dem Top-Befehl sehen wir, dass der Java-Prozess 961,6 % der CPU nutzt, und stellen fest, dass die Prozess-ID 55790 ist.

Verwenden Sie den verfeinerten Top-Befehl, um die CPU-Auslastung jedes Threads in diesem Java-Prozess anzuzeigen:

#top -H -p 55790 

Es ist ersichtlich, dass ein Thread namens „scheduling-1“ einen großen Teil der CPU belegt und 42,5 % erreicht. Der nächste Schritt besteht also darin, herauszufinden, was dieser Thread macht.

Um herauszufinden, was die Threads tun, generieren Sie mit jstack einen Thread-Snapshot.
Die jstack-Ausgabe ist groß und wird normalerweise in eine Datei geschrieben:

jstack 55790 > 55790.log

Öffnen Sie 55790.log und suchen Sie den Thread mit dem Namen „scheduling-1“ , den Sie in Schritt 4 gefunden haben. Sein Thread-Stapel ist:

Wenn man sich den Funktionsaufruf von AbstractExecutorService#submit ansieht, bedeutet dies, dass es sich um einen periodischen Task-Thread handelt, der von Spring Boot gestartet wird, der Tasks an den Thread-Pool übermittelt und viel CPU verbraucht.

Kontextwechsel-Overhead?

Nachdem Sie den oben beschriebenen Prozess durchlaufen haben, können Sie häufig Threads lokalisieren, die viel CPU-Leistung verbrauchen und Fehlercodes aufweisen, wie z. B. tote Schleifen. Aber in diesem Fall: Der Java-Prozess belegt 961,6 % der CPU, während der Thread „Scheduling-1“ nur 42,5 % der CPU belegt. Wer belegt dann den Rest der CPU?

In Schritt 4 gibt es viele Threads mit dem Namen „pool-1-thread-x“ in der Threadliste, die mit dem Befehl top -H -p pid angezeigt wird. Ihre individuelle CPU-Auslastung ist nicht hoch, aber die Anzahl scheint relativ groß zu sein. Wie Sie vielleicht schon vermutet haben, sind dies die Threads, die die Arbeit im Thread-Pool erledigen. Wird die verbleibende CPU von diesen Threads verbraucht?

Sie müssen sich auch die Ausgabeergebnisse von jstack ansehen, vor allem um zu sehen, ob die Threads in diesen Thread-Pools wirklich arbeiten oder „ruhen“.

Es wurde festgestellt, dass sich diese „Pool-1-Thread-x“-Threads grundsätzlich im Wartezustand befinden.

  • Blockieren bezeichnet einen Zustand, in dem ein Thread blockiert ist, weil er in einem kritischen Abschnitt auf eine Sperre (Schlüsselwort Lock oder synchronisiert) wartet. Bitte beachten Sie, dass der Thread in diesem Zustand die Sperre noch nicht erhalten hat.
  • Warten bedeutet, dass ein Thread die Sperre erhalten hat, aber warten muss, bis andere Threads bestimmte Vorgänge ausführen. Wenn beispielsweise die Methode Object.wait, Thread.join oder LockSupport.park aufgerufen wird, wird der Wartezustand aktiviert. Voraussetzung ist, dass der Thread die Sperre bereits erhalten hat und die Sperre vor dem Eintritt in den Wartezustand automatisch auf Betriebssystemebene freigegeben wird. Wenn die Wartebedingung erfüllt ist, wird die Methode Object.notify oder LockSupport.unpark extern aufgerufen und der Thread konkurriert erneut um die Sperre. Erst nachdem die Sperre erfolgreich erhalten wurde, kann er in den Runnable-Zustand wechseln und die Ausführung fortsetzen.

Zurück zu unseren Threads „pool-1-thread-x“: Diese Threads befinden sich im Status „Warten“. Aus dem Thread-Stapel können wir erkennen, dass diese Threads auf den Aufruf der Methode getTask „warten“. Der Thread versucht, eine Aufgabe aus der Warteschlange des Thread-Pools abzurufen, aber die Warteschlange ist leer, sodass er über den Aufruf LockSupport.park in den Status „Warten“ wechselt. Wie viele „Pool-1-Thread-x“-Threads gibt es? Mit dem folgenden Befehl wird die Anzahl der Threads gezählt. Das Ergebnis ist 4096, was genau der Anzahl der Threads im Thread-Pool entspricht.

grep -o 'pool-2-thread' 55790.log | wc -l

Wer verbraucht die verbleibende CPU?
Wir sollten einen CPU-Overhead beim Kontextwechsel vermuten, da wir im Java-Prozess eine große Anzahl Threads sehen.

Verwenden wir den Befehl vmstat, um die Aktivität beim Kontextwechseln von Threads auf Betriebssystemebene anzuzeigen:

Die Spalte cs gibt die Anzahl der Thread-Kontextwechsel an und in die Anzahl der CPU-Interrupts. Wir haben festgestellt, dass diese beiden Zahlen sehr hoch sind, was im Grunde unsere Vermutung bestätigt, dass Thread-Kontextwechsel viel CPU verbrauchen.
Welcher Prozess hat es verursacht?

Stoppen Sie das Spring Boot-Programm und führen Sie den vmstat-Befehl erneut aus. Sie werden sehen, dass sowohl in als auch cs deutlich gesunken sind, was bestätigt, dass der Java-Prozess, der den Thread-Kontextwechsel-Overhead verursacht, 55790 beträgt.

Zusammenfassen

Wenn die CPU-Auslastung zu hoch ist, suchen Sie zunächst nach dem Prozess, der dies verursacht. Verwenden Sie dann den Befehl top -H -p pid, um den entsprechenden Thread zu finden.
Zweitens müssen wir den Status der Threads über jstack überprüfen, um die Anzahl der Threads oder den Status der Threads anzuzeigen. Wenn die Anzahl der Threads zu groß ist, kann vermutet werden, dass der Overhead durch das Umschalten des Thread-Kontexts verursacht wird. Wir können dies über die beiden Tools vmstat und pidstat bestätigen.

Dies ist das Ende dieses Artikels zur Lösung des Problems, dass der Tomcat-Prozess zu viel CPU beansprucht. Weitere Informationen zum Thema „Tomcat-Prozess beansprucht zu viel CPU“ finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den verwandten Artikeln weiter unten. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • SpringBoot startet eingebettete Tomcat-Implementierungsschritte
  • Tomcat unterbricht den übergeordneten Delegierungsmechanismus, um eine Isolierung von Webanwendungen zu erreichen
  • Eine kurze Erläuterung, wie Tomcat den übergeordneten Delegationsmechanismus unterbricht
  • Verwenden Sie Tomcat, um die gemeinsam genutzte Bibliothek so einzurichten, dass sie dasselbe JAR teilt.
  • Fünfzehn Tomcat-Interviewfragen, eine seltene Gelegenheit!

<<:  Einfaches Webdesign-Konzept – Farbabstimmung

>>:  MySQL query_cache_type-Parameter und Verwendungsdetails

Artikel empfehlen

Beispiele für die Erstellung und Verwendung von MySQL-Triggern

Inhaltsverzeichnis Was ist ein Auslöser Erstellen...

Docker führt Vorgänge mit dem angegebenen Speicher aus

wie folgt: -m, --memory Speicherlimit, das Format...

MAC+PyCharm+Flask+Vue.js-Build-System

Inhaltsverzeichnis Konfigurieren Sie node.js+nvm+...

HTML-, CSS- und JS-Kompatibilitätsbaum (IE, Firefox, Chrome)

Was ist ein Baum im Webdesign? Einfach ausgedrückt...

Vue implementiert einen Scrollbar-Stil

Zuerst wollte ich den Stil der Bildlaufleiste des...

Vue implementiert den Schnittstellen-Gleiteffekt

In diesem Artikelbeispiel wird der spezifische Co...

...

So erstellen Sie Ihre erste React-Seite

Inhaltsverzeichnis Was ist Rract? Hintergrund Rea...

Vertieftes Verständnis des Implementierungsprinzips des Require Loader

Vorwort Wir sagen oft, dass Node keine neue Progr...

Schreiben Sie einen formellen Blog mit XHTML CSS

Der vollständige Name von Blog sollte Weblog sein,...

Verbesserung der Wirkung von Hyperlinks im Webdesign und in der Produktion

Hyperlinks ermöglichen es Benutzern, sofort von ei...