2016-06-20 4 views
1

Wir führen eine Webanwendung mit Java7 und Tomcat7. In unserer Anwendung hat die Performance ziemlich plötzlich gelitten. Die durchschnittliche Antwortzeit verdoppelte sich und in Spitzenzeiten wurde das Problem sogar noch schlimmer.Java Deadlock verschlechtert die Leistung

Wir druckten einen Thread-Dump aus und fanden einen Thread herum, der ewig auf einen Zustand wartete. Wir haben mehrere Thread-Dumps gemacht und der Zustand dieses Threads hat sich nie geändert.

"logback-66215" daemon prio=10 tid=0x00007f86f4115800 nid=0x3758 waiting on condition [0x00007f868d817000] 
    java.lang.Thread.State: WAITING (parking) 
     at sun.misc.Unsafe.park(Native Method) 
     - parking to wait for <0x00007f8ddf241fa8> (a java.util.concurrent.SynchronousQueue$TransferStack) 
     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) 
     at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458) 
     at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359) 
     at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:925) 
     at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
     at java.lang.Thread.run(Thread.java:745) 

Die Referenzen in diesem Thread zu 0x00007f868d817000 und 0x00007f868d817000 wurden in dem Thread-Dump nicht gefunden.

Nach dem Neustart Tomcat war der Thread weg und Leistung war wie es sein sollte.

Wir führen es auf einem Server mit 12 Kernen. Wir überwachen die CPU-Auslastung, sehen aber keine Spitze. Bei Spitzenlast wegen etwa 500 Anfragen/Sekunde stieg die CPU-Auslastung auf 800%, stieg jedoch nicht weiter auf bis zu 1200% (was das Maximum ist). Es hat einfach aufgehört zu steigen, als es 800% erreichte und dann waren die Performance-Probleme natürlich sehr schlecht.

Ich verstehe nicht genug über die Interna Threading, CPU, Unterbrechungen, um diese Situation vollständig zu verstehen. Ich möchte dieses Problem wirklich auf einer tieferen Ebene verstehen.

Jetzt meine Frage: Kann mir jemand erklären, warum eine solche Blockade so viel Ärger verursacht? Warum wird es nicht in der CPU-Auslastung angezeigt, sodass wir eine voll ausgelastete CPU sehen? Oder ist es nur ein Problem mit Kontextwechsel?

Antwort

0

Korrigieren Sie mich, wenn ich falsch liege, aber basierend auf dem obigen Thread-Dump und dem Vorhandensein einer SynchronousQueue würde ich annehmen, dass Sie einen CachedThreadPoolExecutor (Executors.newCachedThreadPool()) verwenden, um einige Aufgaben auszuführen.

Der Speicherauszug wäre also der eines zwischengespeicherten Threads, der einfach darauf wartet, dass ein Job in den Threadpool eingereiht wird. Hier ist nichts falsch, das ist kein Deadlock - ein echter Deadlock würde ohnehin im Thread-Dump explizit als solcher angegeben.

Wie bei der CPU-Auslastung verbraucht ein Thread, der in den Status WAITING versetzt wird, keine CPU-Zyklen - er ist nicht einmal zur Ausführung geplant.

Woher kommt Ihr Leistungsproblem?

Schwer zu sagen, aber wenn ich Sie wäre, würde ich vermeiden, einen CachedThreadPool zu verwenden, da es fleißig so viele Threads erstellt, um die Aufträge auszuführen, auch wenn es bedeutet, den gesamten Speicher Ihres Servers zu essen reservierter Speicher für seinen Stack, der mindestens 100k ist) und CPU (dein Scheduler wird verrückt, wenn zu viele Threads zu verwalten sind).

Sie können einen ThreadPoolExecutor manuell konfigurieren (im Gegensatz zur Verwendung der Executors.new* Factories), um die maximale Anzahl von Threads, die Größe und den Typ der Warteschlange und die Backoff-Strategie im Falle einer großen Menge von Jobs auswählen zu können Kommen.

Verwandte Themen