Mittwoch Apr 29, 2015

Debugging des Autodiscovery

Die Autodiscovery Fähigkeiten des Enterprise Managers 12c sind ein mächtiges und hilfreiches Werkzeug wenn es darum geht große, weit verteilte und/oder unbekannte Umgebungen schnell und effizient als Ziele in den Enterprise Manager zu integrieren.
Voraussetzung für ein ordnungsgemäßes Funktionieren des Autodiscovery ist allerdings, dass die Installationen der Oracleprodukte, die Oracle Homes und ganz besonders das Installer Repository "sauber" und frei von "Altlasten" sind.
Bei Entwicklungs- und Testumgebungen, die häufigen Wechseln unterliegen aber auch bei gewachsen Produktivumgebungen trifft dies nicht immer zu. Der normale Betrieb wird dadurch nicht weiter beeinflusst. das Autodiscovery kann an solchen Fehlkonfigurationen allerdings scheitern ohne das eine sinnvolle Fehlermeldung weiterhilft.

Zum Glück beruht das gesamte Autodiscovery, wie auch nahezu alle anderen Aktionen des Agent, auf Perl-Scripten, die auch direkt gestartet werden können und in diesem Fall etwas gesprächiger sind. Durch diese Hinweise und die schnelleren Turnaroundzeiten durch das direkte Ausführen, lässt sich meist schnell die Ursache finden an der das Autodiscovery scheitert.

Die vom Agent aufgerufenen Scripte finden sich in den Verzeichnissen unterhalb des Verzeichnisses <$AGENT_HOME>/plugins.
Welche Scripte vom Autodiscovery verwendet werden (können) und was sie finden ist im jeweiligen Verzeichnis in einer Datei namens "autodiscoverable.lst" vermerkt. Mit

cd $AGENT_HOME/plugins
find ./ -name autodiscoverable.lst

kann man sich eine Übersicht verschaffen.

Der Autodiscovery-Vorgang des EM startet mit dem Aufruf Scripts "OracleHomeDiscovery.p", welches eine XML-Datei mit allen gefunden Oracle Homes und deren Parameter zurück gibt.
Das Script liest nur aus und ändert nichts, kann also gefahrlos ausgeführt werden um in einem ersten Schritt zu klären, ob alle vorhanden Homes gefunden und richtig erkannt werden.
export AGENT_HOME=/opt/oracle/em/agent12104
export LD_LIBRARY_PATH=$AGENT_HOME/core/12.1.0.4.0/lib

$AGENT_HOME/core/12.1.0.4.0/perl/bin/perl -I$AGENT_HOME/core/12.1.0.4.0/sysman/admin/scripts/ \
-I$AGENT_HOME/core/12.1.0.4.0/perl/lib/site_perl/5.10.0/x86_64-linux-thread-multi \
$AGENT_HOME/plugins/oracle.sysman.oh.discovery.plugin_12.1.0.4.0/OracleHomeDiscovery.pl 

Die Ausgabe sieht dann (beispielhaft) so aus:

<Targets>
    <Target TYPE="oracle_home" NAME="OraDB12Home2_24_em12c.demo.com" DISPLAY_NAME="OraDB12Home2_24_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/db/db121020" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
    </Target>
    <Target TYPE="oracle_home" NAME="OracleHome_31_em12c.demo.com" DISPLAY_NAME="OracleHome_31_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/mw/12.1.3.0.0" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
    </Target>
    <Target TYPE="oracle_home" NAME="Oracle_BI11_3_em12c.demo.com" DISPLAY_NAME="Oracle_BI11_3_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/em/oms12104/oms12104/Oracle_BI1" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
        <Property NAME="MW_HOME" VALUE="/opt/oracle/em/oms12104/oms12104" />
    </Target>
    <Target TYPE="oracle_home" NAME="WebLogicServer10_3_6_0_em12c.demo.com_2346" DISPLAY_NAME="WebLogicServer10_3_6_0_em12c.demo.com_2346">
        <Property NAME="HOME_TYPE" VALUE="W" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/em/oms12104/oms12104/wlserver_10.3" />
        <Property NAME="MW_HOME" VALUE="/opt/oracle/em/oms12104/oms12104" />
    </Target>
    <Target TYPE="oracle_home" NAME="agent12c1_10_em12c.demo.com" DISPLAY_NAME="agent12c1_10_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/em/agent12104/core/12.1.0.4.0" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
    </Target>
    <Target TYPE="oracle_home" NAME="common12c1_22_em12c.demo.com" DISPLAY_NAME="common12c1_22_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/em/oms12104/oms12104/oracle_common" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
        <Property NAME="MW_HOME" VALUE="/opt/oracle/em/oms12104/oms12104" />
    </Target>
    <Target TYPE="oracle_home" NAME="oms12c1_4_em12c.demo.com" DISPLAY_NAME="oms12c1_4_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/em/oms12104/oms12104/oms" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
        <Property NAME="MW_HOME" VALUE="/opt/oracle/em/oms12104/oms12104" />
    </Target>
    <Target TYPE="oracle_home" NAME="webtier12c1_23_em12c.demo.com" DISPLAY_NAME="webtier12c1_23_em12c.demo.com">
        <Property NAME="HOME_TYPE" VALUE="O" />
        <Property NAME="INSTALL_LOCATION" VALUE="/opt/oracle/em/oms12104/oms12104/Oracle_WT" />
        <Property NAME="INVENTORY" VALUE="/opt/oracle/oraInventory" />
        <Property NAME="MW_HOME" VALUE="/opt/oracle/em/oms12104/oms12104" />
    </Target>
</Targets>

Die Informationen bezieht das Script im wesentlichen aus dem Installer-Repository (.../oraInventory/ContentsXML/inventory.xml), sollte das Script also Fehlermeldungen ausgeben oder nicht alle erwarteten Homes finden, dann ist die Ursache meistens ein inkonsistentes Installerrepository (z.B wenn Installationen gelöscht anstatt deinstalliert wurden).

Nach dem initialen Script zum Discovern der OracleHomes werden im Anschluss produktspezifische Scripte aufgerufen. Für Weblogic Domänen ist dies

export AGENT_HOME=/opt/oracle/em/agent12104
export LD_LIBRARY_PATH=$AGENT_HOME/core/12.1.0.4.0/lib
export DISC_ROOT=$AGENT_HOME/plugins/oracle.sysman.emas.discovery.plugin_12.1.0.7.0

$AGENT_HOME/core/12.1.0.4.0/perl/bin/perl -I$AGENT_HOME/core/12.1.0.4.0/sysman/admin/scripts/ \
-I$AGENT_HOME/core/12.1.0.4.0/perl/lib/site_perl/5.10.0/x86_64-linux-thread-multi \
$AGENT_HOME/plugins/oracle.sysman.emas.discovery.plugin_12.1.0.7.0/scripts/wls/autodisco/fmw_discover.pl

Der Aufruf sollte eine XML-Datei aller erkennbaren Domänen liefern die diesem Beispiel ähnelt.

<Targets>
  <Target TYPE="weblogic_domain" NAME="/base_domain" DISPLAY_NAME="base_domain" ON_HOST="em12c.demo.com">
    <Property NAME="DOMAIN_HOME" VALUE="/opt/oracle/mw/12.1.3.0.0/domains/base_domain"/>
    <Property NAME="version" VALUE="12.1.3.0.0"/>
    <Property NAME="Protocol" VALUE="t3s"/>
    <Property NAME="Port" VALUE="7002"/>
    <Property NAME="MachineName" VALUE="em12c.demo.com"/>
  </Target>
  <Target TYPE="weblogic_domain" NAME="/Farm_GCDomain/GCDomain_em12c.de.oracle.com_7102" DISPLAY_NAME="GCDomain" ON_HOST="em12c.demo.com">
    <Property NAME="DOMAIN_HOME" VALUE="/opt/oracle/em/oms12104/gc_inst/user_projects/domains/GCDomain"/>
    <Property NAME="version" VALUE="10.3.6.0"/>
    <Property NAME="Protocol" VALUE="t3s"/>
    <Property NAME="Port" VALUE="7102"/>
    <Property NAME="MachineName" VALUE="em12c.demo.com"/>
  </Target>
</Targets>

Hierzu werden erst wieder die passenden OracleHomes gesucht (mit der gleichen Routine, die auch das initiale Script verwendet. Wenn das also schon nicht sauber durchläuft, dann läuft dieses Script auch nicht sauber!) und dann in diesen Homes die Datei "domainlocation.properties" an unterschiedlichen Stellen gesucht und ausgelesen. In dieser Datei stehen die konfigurierten Domänen mit ihren DomainHomes.
In diesen DomainHomes wird jetzt jeweils die Datei <DOMAIN_HOME>/config/config.xml ausgelesen und die wesentlichen Parameter der Domänen zurück gegeben.
Der Autodiscovery-Vorgang bzw. das manuelle Aufrufen der Perlscripte für das Datenbankdiscovery funktioniert analog.

 An dieser Stelle endete der eigentliche Autodiscovery-Vorgang, weitergehende Discoveryschritte benötigen jetzt die Ein- bzw. Übergabe von Parametern zur genaueren Lokalisierung (Hostname, Port, etc) und Authentisierung (Benutzername, Passwort). Auf der Enterprisemanager Website sind diese Schritte unter dem Menuepunkt "promote" (Vorziehen) zu finden und gehören nicht mehr zum Autodiscovery im engeren Sinn.

Ulf Lämmerhirt

Freitag Mai 02, 2014

JVMD Teil 2 - Java Virtual Machine Diagnostic Best Practices

JVMD Teil 2 - Echzeit-Diagnose, Thread- und Diagnostic-Threadshots 

Einleitung

Dies ist der zweite Teil der Reihe "Java Virtual Machine Diagnostic" Best-Practices. In diesem Teil wird näher auf die Komponenten Echtzeit-Diagnose (Real-Time-Analysis) und Snapshots eingegangen. Die Echtzeit-Analyse ist für einen Einblick in die aktuellen Vorgänge innerhalb der JVM. Snapshot bedeutet in diesem Zusammenhang, dass die Informationen für eine spätere Analyse verwendet werden können. Die Snapshots werden in zwei Bereiche unterteilt, der Thread-Snapshot und der Diagnostic-Snapshot. Der Thread-Snapshot bietet sehr detaillierte Offline-Thread-Diagnose-Möglichkeiten in einem begrenzten Zeitraum (unter Einer Minute). Der Diagnostic Snapshot ermöglicht dies ebenfalls, allerdings nicht so detailliert und für einen größeren Zeitraum (mehrere Stunden).

So können durch diese drei Möglichkeiten verschiedene Fälle abgedeckt werden, zum Beispiel:

Das System hat akute Probleme und "hängt" durch zum Beispiel einen Thread-Lock -> Einsatz von Echtzeit-Diagnose (Real-Time-Analysis)

Ein Business-Critical-System hat akute Probleme und "hängt" durch zum Beispiel einen Thread-Lock. Ein Neustart muss sofort durchgeführt werden -> Einsatz von Thread-Snapshots

Das System hat Performance-Schwierigkeiten die unregelmäßig auftreten, die Lösung: Eine Langzeit-Analyse -> Einsatz von Diagnostic-Snapshots

Echtzeit-Diagnose

Die Echtzeit-Diagnose ermöglich Einsicht in den aktuellen Zustand der JVM. Mögliche Use-Cases sind:

Identifizierung langlaufender Threads (IO,CPU,RMI), Dead-Locks, langlaufende SQL-Statements etc.

Wie kommt man zur Echtzeit Diagnose?

Es gibt mehrere Möglichkeiten zur Echtzeit-Diagnose (Active Threads) zu gelangen:

a.) Über das Hauptmenü: Targets -> Middleware -> Bei Anzeige aller Middleware-Ziele, Aufklappen der Domäne  -> Aufklappen *_jvmpool -> *_jvm Auswählen -> "Live Thread Analysis" klicken

b.) Über das WebLogic-Server-Menue: Kontext Menü -> Diagnostic -> "Live Thread Analysis"

c.) Über die Suche: Suchen jvm -> Mauszeiger auf gewünschte JVM -> Rechte Maustaste (Kontext-Menü) -> "Live Thread Analysis"

d.) Über "All-Targets: Im Baum Middleware, Java Virtual Machine auswählen -> Mauszeiger auf gewünschte JVM -> Rechte Maustaste (Kontext-Menü) -> "Live Thread Analysis"

Welche Möglichkeiten bietet die Echtzeit-Diagnose?

Durch das Öffnen der "Live Thread Analyse" Seite wird eine Momentaufnahme des aktuellen Thread-Status gespeichert und angezeigt. Diese Ansicht bleibt so lange erhalten, bis die Seite manuell Erneuert wird. Dieser Refresh kann durch Einstellen des Auto-Refresh auf 30 Sekunden, 1 Minute oder einem eigenen Zeitinterval fixiert werden. 

Die Seite unterteilt sich in die Bereiche: JVM, JVM Threads, Thread Details, Thread Info und Thread Stack. Im Bereich JVM ist eine Auflistung des allgemeinen Zustand der JVM zum Zeitpunkt der Anforderung der Echtzeitanalyse. Der Bereich JVM Threads zeigt alle aktiven Threads an, die zum Zeitpunkt der Anforderung in der JVM waren. Durch setzten des Häkchens "Show Idle Threads" werden auch die Idle-Threads dargestellt. In der Tabellenansicht der JVM Threads werden folgende Informationen dargestellt: Thread Name, Request (Welcher HTTP Request hat den Thread erzeugt), Laufzeit, OS Process ID und Sub-Process-ID, momentan ausgeführter Methodenaufruf, Dateiname der Java Datei, Line of Code, Thread-Status des aktuellen Threads, Wait-On, Art des Wait-Requests, Lock Held, ECID (siehe Blog-Eintrag über ECID) und RID.

Die Relationship ID (RID) gibt an in welcher Position des Aufruf-Baums eines Multi-Threads sich die Sub-Threads befinden. Die erste Nummer ist üblicherweise Null, eine Eins signalisiert, dass es nicht möglich ist die anderen Sub-Tasks zuzuordnen.

Beispiel:

Root Thread, ECID = 007, RID = 0

Sub Task, ECID = 007, RID = 0:1

Zweite Sub-Task, ECID = 007, RID = 0:1:1

Paralleler Task vom Zweiten Sub-Task, ECID = 007, RID = 0:1:2

In den Thread Details wird angezeigt welchen Thread Stack der ausgewählte Thread enthält. Der Thread Stack enthält die Aufruf-Hierarchie des ausgewählten Threads. Es werden alle Methodenaufrufe angezeigt, die in dem ausgewählten Thread durchgeführt wurden. Der Bereich Thread Info enthält detaillierte Informationen zum ausgewählten Thread. Es handelt um die gleichen Informationen wie in der der Tabelle JVM Threads in einer anderen Darstellungsweise. Die Unterscheidung zur Tabellendarstellung liegt in der weiterführenden Verarbeitung der Einträge. Zum Beispiel sind die Parameter State, ECID, State, Wait Request und Lock Held auswählbar. Bei der Auswahl eines Parameter-Links wird eine detailliertere Diagnose aufgerufen. Wählt man z.B. das im Parameter Wait-Request enthaltende SQL-Statement auf, wir man automatisch auf die SQL-Diagnose der Datenbank weitergeleitet.

Bild 1: Ansicht der Real-Time-Analyse Seite

Die Tabelle des Thread Stack ermöglicht es den Methodenaufruf, Tiefe des Aufrufs innerhalb des Threads, Dateiname in der die Methode aufgerufen wird und die Line-of-Code in der sich der Methodenaufruf befindet. Diese Informationen helfen den Entwicklern exakt die Stelle zu lokalisieren, in der die Methode aufgerufen wird. Diese Funktion ist sehr hilfreich im Debuggen des Quellcodes. 

Der Button "Browse Local Objects" ermöglicht das Anzeigen aller Parameter, die im Aufruf der Methode übergeben worden sind. Wählt man eine Methode aus und drückt den Button werden alle Object Parameter angezeigt. Diese Funktion erlaubt das Identifizieren eines einzelnen Request inklusive Parameter, dadurch können die z.B. die fachlichen Eingaben ermittelt werden, die dazu geführt haben das ein Fehler auftritt.

Eine wichtige Information an dieser Stelle: Die Abfrage der Parameter (Browse Local Object Button) erfolgt in Echtzeit. Das heißt wenn das Objekt zur Zeit der Abfrage im Speicher nicht mehr vorhanden ist, kann es auch keine Parameter anzeigen. Aus diesem Grund eignet sich diese Methode zum Auffinden von Langläufern und nicht um Objekte zu Analysieren die nur für kurze Zeit im Speicher vorhanden sind. Aus diesem Grund ist im oberen, linken Bereich des Pop-Up-Fensters eine Export-Funktion, die es erlaubt die ermittelten Informationen für eine nachgelagerte Analyse in eine Datei zu Exportieren.

Snapshots

Wie in der Einleitung bereits beschrieben existieren zwei Snapshot-Funktionen: Thread Snapshot und Diagnostic Snapshot. Der Thread Snapshot eignet sich für die sehr detaillierte Kurzzeitanalyse und der Diagnostic Snapshot für die eine Langzeitanalyse bei z.B. länger auftretenden Performance-Engpässen.

Thread Snapshot

Um einen Thread Snapshot zu erzeugen navigiert man in das WebLogic Server bzw. WebLogicServer_Name_jvm Kontext-Menü und wählt den Punkt Thread Snapshot aus. Die nachfolgende Webseite enthält eine Tabelle mit den bereits erzeugten Thread Snapshots. Die Snapshots können gelöscht, analysiert, exportiert oder erzeugt werden. Wichtig: In dieser Tabelle werden sowohl die Thread Snapshots wie auch die Diagnostic Snapshots angezeigt. Die Unterscheidung zwischen diesen beiden Typen erfolgt über die Duration (Dauer) der Snapshots. Alles im Sekunden-Bereich deutet auf einen Thread Snapshot und alles im Stunden/Tage-Bereich auf einen Diagnostic Snapshot.

Um einen Thread Snapshot zu erzeugen drückt man den "Create"-Button und erhält auf der nachfolgenden Seite die Aufforderung Parameter einzugeben. Die Parameter bedeuten folgendes:

  • Poll Intervall (ms): Gibt die zeitlichen Abstände zwischen den Thread-Dumps an. Je geringer das Interval, desto detaillierter die Informationen. Das voreingestellte Intervall von 300 ms ist Ideal. Eine Verringerung erzeugt zu viel Last auf dem überwachten System.
  • Poll Duration (sec): Gibt an wie lange der Snapshot-Vorgang durchgeführt werden soll. Hier empfiehlt es sich dies nicht länger als 30 Sekunden durchzuführen, da ansonsten zu viel Last auf dem überwachten System erzeugt wird.
  • Desciption: Eine Möglichkeit Kommentare für den Erzeuger des Thread Snapshots einzutragen
  • Thread Detail: Gibt an ob Detaillierte Angaben über die Threads gespeichert werden sollen. Dieser Parameter sollte immer gesetzten bleiben, da ansonsten keine Informationen über den Aufruf-Stack der Methoden gesammelt werden.
  • Try Changing Threads: Bei schnell wechselnden Threads, kann es sein das während der Snapshot Phase der Trace den Zustand ändert. Mit diesem Parameter wird der Thread im aktuellen Zustand gehalten und der Snapshot wird erzeugt.
  • Include Network Waits: Normalerweise werden Threads im Status Network Wait nicht aufgezeichnet. Sollte dies gewünscht sein, muss man den Haken an dieser Stelle setzten.
  • All Threads: Es werden alle Threads aufgezeichnet, auch die nicht Aktiven.
  • Allow Trace Interrupt: Angeblich soll man den Trace unterbrechen können. Ich habe es bis jetzt allerdings nicht geschafft das Erzeugen des Snapshots zu unterbrechen auch nicht bei gesetzten Flag.

Die Analyse der vorhandenen Snapshots erfolgt nach dem gleichen Muster, wie im ersten Teil dieser Serie erklärt.

Tipp: Die Korrelation der Datenbank Informationen kann nur so lange erfolgen, wie diese Daten in den Datenbank Tabellen (z.B: V$SESSION) vorhanden sind. Daher sollte man entweder die Analyse zeitnah durchführen oder mit dem DBA's eine längere Aufbewahrungszeit in diesen Tabellen vereinbaren. Dies erfolgt mit der PL/SQL Prozedur DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS, eine Beschreibung über die Parameter der Prozedur steht in der Datenbank Dokumentation.

Bild 2: Snapshot Analyse zu einem späteren Zeitpunkt

Diagnostic Snapshot

Beim Diagnostic Snapshot wird ein längerer Diagnosezeitraum für die spätere Analyse gespeichert. Da bei der JVM-Diagnose eine große Datenmenge anfällt, die im Enterprise Manager Cloud Control Repository gespeichert wird, werden die historischen Daten der JVM-Analyse einen begrenzten Zeitraum vorgehalten. Um die Daten für einen bestimmten Zeitraum zu konservieren, wird die Funktion Diagnostic Snapshot verwendet.

Voraussetzungen für einen JVMD Diagnostic Snapshot ist ein installierter, konfigurierter und laufender JVMD Agent auf dem Ziel. Nach Auswahl der gewünschten WebLogic Domäne navigiert man auf den "Java Virtual Machine Pool" in der Target Navigation, wählt den gewünschten Server (*_jvm) aus, klickt auf JVM Performance Diagnostics. Auf der JVM Performance Diagnostics Seite befindet sich auf der rechten, oberen Seite der Button "Create Diagnostic Snapshot".

In dem sich nachfolgend öffnen Dialog wird der gewünschte Diagnostic Zeitraum, die berücksichtigten Ziele und der Diagnose Typ angegeben und bestätigt. Der Snapshot wird im Hintergrund durchgeführt und steht anschließend zur Verfügung. Um einen gespeicherten Snapshot zu öffnen, navigiert man wie beschrieben auf das JVMD Target (*_jvm) und wählt aus dem Kontext-Menü den Punkt "Thead Snapshots" aus. In der angezeigten Tabelle sind alle Thread und Diagnostic-Snapshots aufgelistet. Nach Auswahl des gewünschten Snapshots und drücken des Details-Button am oberen Rand der Tabelle wird die Analyse-Komponente aufgerufen. Das detaillierte Vorgehen bei einer Analyse wird im ersten Teil der Serie "JVMD" erklärt.

Bild 3: Erzeugen eines Diagnostic-Snaphots

Fazit

Die Echtzeit-Analyse und die Snapshot-Funktionalität ermöglichen eine sehr genaue Analyse der JVM-Umgebung. Diese Analyse kann sofort oder zu einen späteren Zeitpunkt durchgeführt werden. Ein weiterer Vorteil der Snapshot-Funktionalität ist eine mögliche Übergabe der Analyse-Daten an z.B. einen Entwickler, der dadurch ein Debugging mit Metriken aus dem produktiven Betrieb durchführen kann.


Freitag Jan 24, 2014

JVMD - Java Virtual Machine Diagnostic Best Practices

JVMD Teil 1 - Thread Diagnose Best Practices

Dieser Blog-Eintrag gibt einen Einstieg in das Thema JVMD (Java Virtual Machine Diagnostics) mit dem Oracle Enterprise Manager Cloud Control 12cR3 (FMW Plugin 12.1.0.5). Der Eintrag beleuchtet die Thread-Dump-Analyse-Fähigkeiten von JVMD. Der Eintrag beantwortet folgende Fragen:

Was ist JVMD?

Was kann JVMD?

Wie funktioniert JVMD?

Wie verwende ich JVMD, um Performance Bottlenecks zu finden?

Was ist JVMD?

JVMD steht für Java Virtual Machine Diagnostic und ist eine Komponente des Oracle Enterprise Managers 12c. JVMD ist im aktuellen Release des EM12c voll integriert und wird für viele andere Funktionalitäten verwendet (z. B. Execution Context ID Diagnose).

Was kann JVMD?

JVMD kann, wie der Name schon sagt, Probleme in einer Java VM ermitteln. Hauptsächlich wird es dafür verwendet, JEE-Anwendungen zu diagnostizieren. JVMD ist optimiert für den Oracle WebLogic-Server, kann aber auch für andere JEE-Server wie z. B. JBoss oder WebSphere verwendet werden. JVMD ist darauf ausgelegt, Probleme in Produktionsumgebungen zu finden, d. h. es werden keine Instrumentierungsmechanismen verwendet bzw. die Anwendung muss für JVMD nicht neu gestartet werden. Eine Funktionalität ist die Cross-Tier-Analyse, d.h. Performance-Probleme, die bei Oracle-Datenbank-Zugriffen aus einer JEE-Anwendung erfolgen, werden mit JVMD transparent.

Wie funktioniert JVMD?

JVMD bedient sich eines Betriebssystem-Konzeptes: Thread-Dumps. Mit einem Thread-Dump wird ein Speicherabbild der Server-Java-Threads erzeugt. Dies ist ein oft verwendeter Mechanismus unter Entwicklern, um Probleme innerhalb einer JEE-Applikation zu finden. Dieser Thread-Dump wird z. B. unter einem Linux-Betriebssystem mit dem Befehl kill -3 <PID> erzeugt. Der Kill-Befehl sendet über die Prozess ID ein Signal an den JEE-Prozess, um ein Thread-Abbild in die Standard-Log-Ausgabe zu schreiben. Jeder dieser Thread-Abbilder hat Informationen über den Zustand der Threads und der darin enthaltenen Java-Methoden.

Thread-Zustände können z. B. folgende sein:

NEW - Der Thread wurde erstellt, wird aber noch nicht abgearbeitet

RUNNABLE - Der Thread verwendet CPU und arbeitet Tasks ab

BLOCKED - Der Thread wartet auf einen anderen Thread, um ein Monitor Lock zu erhalten

WAITING - Der Thread wartet auf eine Wait-, Join- oder Park-Methode

etc.

Aus diesen Zuständen werden Performance Bottlenecks oder Locks der Java-Applikationen ermittelt.

Auf die Frage "Warum brauche ich JVMD, wenn ich das auch mit Betriebssystem-Tools kann?", die beim Lesen dieser Zeilen aufkommt, gibt es eine einfache Antwort: "Weil JVMD diesen manuellen Prozess ständig durchführt und so ein vollständiges Bild entsteht." JVMD macht alle zwei Sekunden einen Thread-Dump, speichert diesen im DB-Repository und filtert die unreleveanten Informationen heraus. Man erhält ohne weiteren manuellen Aufwand eine historische und/oder aktuelle Sicht über den Zustand der JEE-Applikation. 

Bild 1: Beispiel einer Ausgabe einer Thread-Dump-Erzeugung

Wie verwende ich JVMD, um Performance Bottlenecks zu finden?

JVMD-Funktionskontrolle

 JVMD ist vollständig in den EM12c integriert. Um JVMD und alle dazugehörigen Komponenten zu installieren, folgt man der offiziellen Dokumentation Link. Nach der Installation und Konfiguration gibt es einen einfachen Weg herauszufinden, ob JVMD korrekt funktioniert. Im EM12c Targets-Menü Middleware auswählen, die Domäne, auf dem der JVMD Agent installiert wurde anklicken, im Navigationsbaum auf der linken Seite den Java Virtual Machine Pool wählen und den gesamten Baum aufklappen. Jeder der WebLogic Server sollte eine _jvm-Endung besitzen. Wenn man nun auf eines der WebLogic-Ziele mit der _jvm-Endung klickt , sieht man im rechten Fenster im unteren Bereich den "Real Time Thread State". Dieser muss einen grünen Pfeil nach oben aufweisen.


Bild 2: Funktionskontrolle JVMD

JVMD Navigation

Java Diagnostic ist in drei Bereiche unterteilt: den JVM-Pool-Bereich, den Einzel-JVM-Bereich und den Realtime-Bereich. Der JVM-Pool-Bereich wird für die Lokalisierung eines Problems und Zuordnung der dazugehörigen JVM verwendet, der Einzel-JVM-Bereich für eine detailierte Untersuchung und eine historische Ursachenanalyse sowie der Realtime-Bereich für die Ursachenanalyse eines aktuellen Problems, wie z. B. ein "hängender" Thread oder Threads mit überdurchschnittlicher Laufzeit.

Beispiel: Analyse einer Applikation, die DB-CPU-Waits verursacht

Dieses Beispiel ist einfach und kann mit der EM12c Standalone-Installation nachvollzogen werden. Es ist nicht nötig, weitere Ziele hinzuzufügen, es wird in diesem Beispiel der OMS selbst analysiert. Dieses Analyse-Beispiel ist hervorragend geeignet, JVMD besser kennen zu lernen, da alle Komponenten verwendet werden.

Schritt 1: Start der Analyse durch die Betrachtung der gesamten Domäne

Auswählen der zu analysierenden Domäne unter Targets -> Middleware (in diesem Fall GCDomain), Öffnen des Baumes Java Virtual Machine Pool auf der linken Seite im Navigationsbereich, Klicken auf den GCDomain_jvmpool. Diese Seite dient als Einstiegsseite und gibt eine Übersicht über den akuellen Stand der WebLogic-JVMs in der Domäne.

Erklärung der Seiten-Komponenten:

Summary: Zeigt an, ob der Thread-Dump-Mechanismus (Poll Enabled) aktiviert ist und in welchem Intervall ein Thread-Dump erzeugt wird.

Availability: Übersicht über die im Pool enthaltenden JVMs, deren Status und die Verfügbarkeit der letzten 24 Stunden.

Incident: Falls die JVMs Systemfehler beinhalten, wird für jeden Fehler ein Incident im EM12c enthaltenden Incident-Manager erzeugt.

Realtime Thread States: In diesem Bereich wird der aktuelle Zustand der JVMs angezeigt, eine genaue Aufschlüsselung der Spaltenbeschreibung erhält man in der Online-Hilfe des EM12c.

Bild 3: JVMD Pool Homepage

Im nächsten Schritt wird überprüft, welche der JVMs ein Performance-Problem hat. Dazu wird auf JVM Performance Diagnostics oben im rechten Fenster geklickt.

Auf der folgenden Webseite befindet sich eine Übersicht des Verhaltens der JEE-Applikationen bezogen auf die jeweiligen JVMs. Dies betrifft sowohl Custom-Applikationen wie auch den WebLogic Server selber bzw. darauf installierte SOA-Suites, WebCenter etc.

Die Seite enthält folgende Komponenten:

Timeline: Welcher Zeitrahmen soll betrachtet werden, Default-Einstellung ist 24 Stunden.

Server States Charts for Selected Period: Eine grafische Ansicht der Thread-States, der CPU-Utilisierung und des Heap-Speicher Verbrauchs.

Filter Options: An dieser Stelle können für alle Top-Activities Filter-Optionen gesetzt werden. Soll ein gesetzter Filter entfernt werden, wird auf die Textbox mit dem Filter geklickt und der Text gelöscht.

Top Activities: In den Top Activities werden alle Komponenten-Statuten angezeigt, die in den Thread Dumps gefunden worden sind. Top Methods sind die Methoden, die am meisten in den Samples der Thread-Dumps gefunden wurden. Die Top Requests enthalten Informationen über HTTP-/HTTPS-Requests. Der Eintrag "None" bedeutet, dass eine Anforderung nicht von einem HTTP(S)-Aufruf stammt. Die Top DBWait Events beschreiben den Zustand der Datenbank während der Ausführung der SQL-Statements. Top SQL beschreibt die am meisten vorgefundenen SQL-Statements. Die Top Databases zeigen an, welche Datenbank verwendet wurde.

JVMs in Pool: Eine detaillierte Ansicht der "Server States Charts for Selected Period" bezogen auf die einzelnen im Pool vorhandenen JVMs.

Bild 4: Auschnitt JVM Pool Performance Diagnostics

In der Übersicht der "Server Stats Charts for Selected Period" wird auf den ersten Blick klar, welche der JVMs den größten Anteil der Thread-Dumps im DBWait-Status verbringt. Bei einem Blick auf den linken Graphen wird erkennbar, dass der größte Teil des Graphen grün ist. Grün steht für DBWait, wie man in der Agenda unter dem Graphen sieht. Daher liegt der Fokus auf den Datenbank-Events im Bereich "Top Activities". In der Tabelle "Top DBWait Events" ist erkennbar, dass verschiedene Wait-Events auf verschiedene Samples verteilt sind. Ein Sample entspricht jeweils einem Zustand, der in einem Thread-Sample gefunden wurde. Zum Beispiel: Der DBWait Event CPU hat 98 Samples, d. h. in 24 Stunden wurden bei 98 Thread-Dumps die Threads im Zustand DBWait-CPU gefunden. Bei einer Sample-Rate von zwei Sekunden in 24 Stunden (3600 * 24 = 86400 Sekunden/zwei Samples pro Sekunde = 43200 Samples) handelt es sich um 0,2 Prozent. Für den DB Event "wait for unread message on broadcast channel" mit 90323 Samples entspricht dies 200 Prozent. Allerdings agiert der Wait-Event "wait for unread message on broadcast channel" als eine Art Listener für die Anwendung und der Thread-Status ist systemspezifisch, daher wenden wir uns dem DBWait-Event-CPU zu. Dieser CPU-Event deutet an, dass die Datenbank auf CPU-Zeit wartet, um die jeweiligen SQL-Statements zu durchlaufen. 

Schritt 2: Filtern der Thread-States, um das Problem zu lokalisieren

Wird nun auf CPU in der Tabelle "Top DBWait Events" geklickt, erscheint ein Pop-Up-Fenster mit zwei Wahlmöglichkeiten. Beim Klicken auf "OK" wird der DBWait-Event CPU als Filter gesetzt und nur die Methoden, TOP SQLs etc. angezeigt, die mit dem DBWait-Event in Verbindung stehen. Beim Klicken auf den Datenbank-Link im Pop-Up öffnet sich die Active Session History-Diagnose der betroffenen Datenbank und erlaubt es,  die betroffene Session weiter zu diagnostizieren. In unserem Fall wählen wir den Filter DBWait-Event CPU durch Klicken des OK-Buttons und erhalten eine Ansicht aller Aktivitäten, die mit dem DBWait-Event CPU im Zusammenhang stehen.


Bild 5: Ansicht nach setzten des DBWait-Event Filters "CPU"

Bild 5 lässt erkennen, dass durch das Setzen des Filters weniger Top-Methoden, Top Requests und Top SQLs dargestellt werden.

Schritt 3: Lokalisieren Java-Methodenaufrufe zum DBWait-Event "CPU"

Um im dritten Schritt zu ermitteln, welche Methodenaufrufe für die DBWaits verantwortlich sind, wird die Methode(n) mit den höchsten Samples aus der Tabelle "Top Activities" ausgewählt.


Bild 6: Ansicht des Methoden-Aufruf-Stacks für den DBWait-Event CPU

In dieser Ansicht werden die Methodenaufrufe nach dem verursachenden Methodenaufruf durchsucht oder der ausgewählte Methodenaufruf wird als Filter gesetzt. Im Call-Stack ist zu erkennen, dass die Hauptursachen für das DBWait die Methodenaufrufe oracle.sysman.emas.mda.fwk.dal.RawQueryImpl->update und oracle.sysman.emas.mda.fwk.dal.RawQueryImpl->insert sind. Beide Aufrufe sind EM12c-eigene Methoden zur Verwaltung des Enterprise Managers. Durch Drücken des "OK" Buttons wird ein Filter auf diese Methoden gesetzt. Es werden auschließlich die SQL-Statements angezeigt, die durch diese Methodenaufrufe ausgeführt wurden. 

Bild 7: Filtern nach DBWait-Event und Methodenaufruf zur Vorbereitung der SQL-Analyse

Schritt 4: Analyse der verursachenden SQL-Statements

In diesem Fall sind es Fünf SQL-Statements, die für den DBWait-Event CPU verantwortlich sind. Durch Auswählen der SQL-Statements erhält man das detaillierte Statement zur Ansicht.


Bild 8: Anzeige der SQL-Details

Wenn das Datenbank Diagnostic Pack für den Enterprise Manager lizensiert wurde, kann durch Klicken auf den Datenbank-Link im SQL-Detail-Fenster der SQL-Analyzer aufgerufen werden. Diese Datenbank-Analyse-Funktion ermöglicht eine detallierte Betrachtung des SQL-Statements.


Bild 9: Aufrufen der SQL Details im Datenbank SQL-Analyzer

Fazit

Dieser Blog-Eintrag gibt einen Einstieg in die Analyse von Performance Bottlenecks innerhalb von JEE-Applikationen mittels JVMD. Das aufgezeigte Beispiel beschreibt die Ursachenermittlung von DBWait-Events. Das weitere Vorgehen, um z. B. Locks oder hohe CPU-Auslastungen zu finden, ist analog zu dem obigen Beispiel.

JVMD bietet noch eine Reihe weitere Funktionalitäten, wie z. B. Echtzeit-Thread-Analyse, Erzeugen von Diagnostic Snapshots, Aufnahme eines detaillierten Thread-Snapshot oder das große Thema Memory-Leak-Analyse. Alle diese Themen werden in nachfolgenden Blogs detailliert beleuchtet. Dieser erste Eintrag in der JVMD-Reihe soll einen Einstieg in das Thema bieten.

About

Dieser deutschsprachiger Blog behandelt alle Themen rund um Oracle Middleware Management mit dem Oracle Enterprise Manager 12c.

Search

Archives
« Juli 2015
MoDiMiDoFrSaSo
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Heute