2016-06-24 4 views
2

Ich versuche, eine Akka App zu profilieren, die ständig bei oder in der Nähe von 100% CPU-Auslastung ist. Ich nahm eine CPU-Probe mit visualvm. Das Beispiel zeigt an, dass 2 Threads 98,9% der CPU-Auslastung ausmachen. 79% der CPU-Zeit wurden für eine Methode ausgegeben, die sun.misc.Unsafe genannt wird. Other answers on SO sagen, dass es nur bedeutet, dass ein Thread wartet, aber in der nativen Implementierungsschicht (außerhalb der JVM).Akka IO App verbraucht 100% CPU

In Fragen ähnlich wie meine, Menschen wurden told to look elsewhere ohne Angabe gegeben. Wo soll ich herausfinden, was die cpu Spitze verursacht?

Die Anwendung ist ein Server, der hauptsächlich Akka IO verwendet, um TCP-Socket-Verbindungen zu überwachen.

+0

Sie sagen, Sie haben eine CPU-Probe genommen. Was genau meinst du? –

+0

sun.misc.Unsafe ist keine Methode, es ist eine Klasse. Bitte zeigen Sie die vollständige Stack-Trace. –

Antwort

2

Ohne den Quellcode zu sehen oder zu wissen, über welchen IO-Kanal Sie sprechen (Sockets, Dateien, usw.), gibt es kaum einen Einblick, den Ihnen jemand hier geben kann.

Ich habe jedoch einige ziemlich allgemeine Vorschläge.

Zuerst, sollten Sie reaktive Techniken und reaktive IO in Ihrer Anwendung verwenden. Dieses Problem kann auftreten, weil Sie den Status einiger Ressourcen in einer engen Schleife abrufen oder einen blockierenden Aufruf verwenden, wenn Sie einen reaktiven verwenden sollten. Dies neigt dazu, ein Anti-Pattern- und ein Performance-Drain genau zu sein, weil Sie CPU-Zyklen ausgeben können, die nichts als "aktiv warten" tun. Ich empfehle doppelte Kontrolle für:

  • Ressource Polling
  • Blockierung auf einem Future
    • System ruft
    • Plattenwallungen
    • warten ruft, wenn es um map stattdessen angemessen wäre es

Zweitens, sollten Sie nicht Mutexes oder andere Thread-Synchronisation in Ihrer Anwendung verwenden. Wenn ja, dann leiden Sie möglicherweise an einer Live-Sperre. Im Gegensatz zu Dead-Locks treten bei Live-Locks Symptome wie 100% CPU-Auslastung auf, da Threads immer wieder Concurrency-Primitive sperren und entsperren, um "alle zu fangen". Wikipedia hat eine nette technische Beschreibung, wie ein Live-Schloss aussieht. Mit Akka sollten Sie keine Mutexes oder Grundelemente für die Thread-Synchronisation benötigen. Wenn Sie dann sind, müssen Sie wahrscheinlich Ihre Anwendung neu entwerfen.

Drittens, sollten Sie IO (sowie Fehlerbehandlung wie Wiederverbindungsversuche) Drosselung sein. Dieses Problem kann auftreten, weil Ihr System keine effektive Drosselung aufweist. Oft verlassen wir bei Datenkanälen ihre Bandbreite unbeschränkt. Dies kann jedoch ein Problem werden, wenn dieser Kanal 100% Sättigung erreicht und beginnt, Ressourcen von anderen Teilen des Systems zu stehlen. Dies kann zum Beispiel passieren, wenn Sie große Dateien ohne ein vernünftiges Limit verschieben.

Alternativ müssen Sie Verbindungswiederholungen bei Auftreten von Fehlern drosseln, anstatt sie sofort erneut auszuführen. Viele Systeme versuchen, die Verbindung zu einem Server wiederherzustellen, wenn sie ihre Verbindung verlieren. Obwohl dies normalerweise wünschenswert ist, kann dies zu einem problematischen Verhalten führen, wenn Sie eine naive Wiederverbindungsstrategie verwenden.Zum Beispiel vorstellt, einen Netzwerk-Client, der auf diese Weise geschrieben wurde:

class MyClient extends Client { 
... other code... 
    def onDisconnect() = { 
    reconnect() 
    } 
} 

Jedes Mal, wenn der Client für irgendeinen Grund trennt sie versucht, wieder zu verbinden. Sie können sehen, wie dies zu einer engen Schleife zwischen dem Fehlerbehandlungscode und dem Client führen würde, wenn der Wifi-Ausgang oder ein Netzwerkkabel nicht angeschlossen wäre.

Vierte, Ihre Anwendung sollte gut definierte Datenquellen und Senken haben. Ihr Problem könnte durch eine "Datenschleife" verursacht werden, dh durch eine Gruppe von Akka-Akteuren, die nur Nachrichten an den nächsten Akteur in der Kette senden, wobei der letzte Akteur die Nachricht an den ersten Akteur in der Kette zurücksendet. Stellen Sie sicher, dass Sie eine eindeutige und eindeutige Möglichkeit haben, Nachrichten in Ihr System einzugeben und es zu beenden.

Fünftens, Verwenden Sie geeignete Profilierung und Instrumentierung für Ihre Anwendung. Instrumentieren Sie Ihre Anwendung mit der Kamon oder Coda Hale Metrics-Bibliothek.

Die Suche nach einem geeigneten Profiler wird schwieriger, da wir als Gemeinschaft weit davon entfernt sind, ausgereifte Werkzeuge für reaktive Anwendungen zu entwickeln. Persönlich habe ich gefunden visualvm nützlich, aber nicht immer überwältigend hilfreich für die Erkennung von Code-Pfaden, die CPU-gebunden sind. Das Problem besteht darin, dass Stichproben-Profiler nur Daten erfassen können, wenn die JVM einen Sicherheitspunkt erreicht. Dies hat das Potenzial, bestimmte Codepfade zu beeinflussen. Das Problem besteht darin, einen Profiler zu verwenden, der AsyncGetStackTrace unterstützt.

Viel Glück! Und fügen Sie bitte mehr Kontext hinzu, wenn Sie können.

Verwandte Themen