Analyse eines Produktionsausfalls durch Weblogic Compiler Threads

Keine Kommentare

Kürzlich besuchte ich einen Kunden um dessen Anwendungsmonitoring mit AppDynamics weiter zu verbessern. Bei meiner Ankunft wurde ich mit folgenden Worten begrüßt:
„Super, dass Du da bist, Fabian. Wir können Dir ganz interessante Dinge aus dem Monitoring zeigen“. Normalerweise sind Leute aus dem Betrieb sehr besorgt, wenn sie mir so etwas sagen. Doch in diesem Fall waren sie sehr entspannt, fast schon fröhlich. „Wir hatten einen großen Produktionsausfall am Samstag als wir die neue Software live genommen haben. Nichts ging mehr!“ Oh jeh!? Was war passiert? Und warum sind die trotz des Ausfalls so gut gelaunt? Niemand mag Produktionsausfälle am Wochenende. „Ja, das war schon ein langer Samstag, aber immerhin haben wir ein Monitoring was uns gesagt hat was los war“.

Nun, schauen wir uns mal an was an diesem Samstag so passiert ist, und was das Problem war, welches den Ausfall verursacht hat.

Ein Überblick über die Situation

Hier ein Bild von dem was an dem Samstag um 8 Uhr morgens vorgefallen ist.


Für alle diejenigen die AppDynamics nicht kennen, hier eine kurze Einweisung in die Oberfläche:

  • Der größte Bereich ist die sogenannte „Application Flow Map“. AppDynamics erkennt alle Server automatisch und überwacht ihre Kommunikation miteinander.
  • Auf der rechten Seite gibt es einige Statistiken. Wir sehen „Stalls“ und „Abnormal Slow requests“. AppDynamics hat also auch bemerkt, dass etwas nicht so ist wie es sein sollte.
  • Unten sehen wir die historische Ansicht. Da es sich zum Zeitpunkt meiner Analyse um historische Daten älter als 2 Tage handelt, wurden sie schon auf Stundenlevel aggregiert. Zum Zeitpunkt des Ausfalls selbst lagen die Daten minütlich vor.

Da wir zurückblicken sind die historischen Daten für uns am interessantesten.
Wir sehen auf der linken Seite den Serverstart (blaue Icons auf grünem Balken). Die Last auf das System stieg schnell an (grüne Balken). Doch das System brach dann schnell zusammen. Die Antwortzeiten (blaue Linie) stiegen und die Anzahl der Requests ging auf 0 zurück. Die Server waren abgestürzt und mussten neu gestartet werden.
Aber der Restart alleine half nicht. Erst die Korrektur des Problems später normalisierte die Lage 🙂

Was genau war passiert?

Die Server stürzten mit einem OutOfMemory Error ab. In unserer OutOfMemoryError Serie, haben wir bereits einige Probleme diskutiert, doch hier ist ein Neues: „Unable to create native thread“.

Dieser Fehler ist in der Tat sehr interessant. Ausfälle mit einem solchen Fehler deuten eher auf Konfigurationsprobleme oder einem Fehler beim Threadmanagement hin, nicht auf inperformanten Code. Also schaute ich mir die Anzahl der Threads an, welche AppDynamics mitgemessen hat:

Ouch. Das System hatte bereits 1800 Threads erzeugt als es abstürzte.
Was erzeugt also diese Threads? Ich kannte das bereits von anderen Kunden, und auch dieser Kunde konnte anhand von einigen Stall-Snapshots schnell sehen was passiert war. Die JSP Kompilation war schuldig.
Alle Applikationsserver haben die Option JSPs bereits beim Serverstart, oder erst wenn durch den Benutzer angefordert, zu kompilieren. Beide Optionen sind aber problematisch wenn der Server bereits unter hoher Last gestartet wird.
Behoben wurde das Problem am Sonntag Morgen um 4. Jedoch musste das Betriebsteam nicht so lange aufbleiben, das sie bereits gegen Mittag einen qualifizierten Fehlerbericht an Oracle gesendet hatten. Die „Korrektur“ von Oracle erfolgte etwas später. Die notwendige Option selbst ist nirgendwo dokumentiert, zumindest nicht so, dass man sie finden kann ohne sie zu kennen.
Hier ein Screenshot aus AppDynamics, der diese Konfigurationsänderung dokumentiert.

JSP Compiler Threads auf Weblogic begrenzen

Der geheime Schalter war eine Umgebungsvariable die gesetzt werden muss:

BEA_COMPILER_NUM_THREADS = 1

Natürlich ist 1 sehr pessimistisch. Jedoch scheint dies die weit bessere Option zu sein als „unbegrenzt“, was die Standardeinstellung zu sein scheint. Niemand sollte jemals unbegrenzt Threads erzeugen. Klassisch gesehen sollte man nur so viele Threads haben wie sich auch Prozessoren in dem Server befinden. Moderne JVMs können jedoch auch gut 10 mal so viele Threads verwalten, solange sie nicht alle die CPU benötigen. Doch hier hatten wir fast 100 Compiler Threads pro CPU.

Fabian Lange ist Lead Agent Engineer bei Instana und bei der codecentric als Performance Geek bekannt. Er baut leidenschaftlich gerne schnelle Software und hilft anderen dabei, das Gleiche zu tun.
Er kennt die Java Virtual Machine bis in die letzte Ecke und beherrscht verschiedenste Tools, die JVM, den JIT oder den GC zu verstehen.
Er ist beliebter Vortragender auf zahlreichen Konferenzen und wurde unter anderem mit dem JavaOne Rockstar Award ausgezeichnet.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.