Die Aufgabe im vergangenen Projekt war, eine schon länger im Betrieb befindliche Hibernate-Anwendung wieder performanter zu machen. Seit dem Ende der Entwicklungsphase waren schon zwei Jahre ins Land gegangen. Der Umfang an Datenmengen, mit dem die Entwickler noch gewohnt waren zu arbeiten, hatte sich seitdem vervielfacht.
Die Latenzzeiten von Datenbankabfragen und, für den Anwender besonders ärgerlich, die Zeitspannen, in denen sich der Mauscursor als drehende Sanduhr zeigte, bewegten sich mittlerweile im Minutenbereich.
Die Aufgabe war also ganz einfach mit dem Begriff Performance-Optimierung zu beschreiben. Aber wo fängt man an? Der Code ist wie gesagt zwei Jahre alt und in dieser Zeit sind mehrere Entwickler neu ins Projekt eingestiegen und haben es wieder verlassen.Sich den Quellcode anzuschauen und einfach so drauflos zu optimieren, macht wenig Sinn. Profiling-Tools sind das Mittel der Wahl.
Bei großen Enterprise-Anwendungen wie in diesem Fall, also EJB auf JBoss mit Hibernate und einer Oracle-Datenbank im Hintergrund, setzen wir sowohl ein Tool für das Profiling des Java-Quellcodes ein als auch eines für das Profiling der Datenbank-Abfragen. Letzteres wird in diesem Artikel vorgestellt.
Setup
IronTrack ist ein JDBC-Treiber, den man anstelle des eigentlichen Datenbank-Treibers in seiner Anwendung konfiguriert. Alle Queries gehen also über IronTrack und werden erst dann an die Datenbank weitergeleitet. IronTrack schreibt alle Anfragen sowie die dazugehörigen Metadaten (u.a. Verarbeitungsdauer und Anzahl der Ergebnisse) in eine Logdatei. Zudem gibt es eine GUI, die diese Logdatei analysiert.
Hier beschreiben wir am Beispiel eines JBoss-Servers, wie das SQL-Monitoring auf einem Entwickler-Rechner eingerichtet wird. Dazu muss der JBoss ebenfalls lokal auf dem Rechner laufen. Der Zugriff auf einen entfernten JBoss ist ebenfalls möglich, sofern ein TCP-Port freigeschaltet werden kann, über den sich die IronTrack-GUI mit der JDBC-Komponente verbinden muss. IronTrack funktioniert mit allen Java-Anwendungen, die über JDBC auf eine Datenbank zugreifen, man ist also nicht auf JBoss beschränkt.
Das Setup ist einfach. Man führt den JAR-Installer auf seinem lokalen Rechner aus.
Im Installationsverzeichnis befinden sich drei Jar-Dateien. Diese werden in das Verzeichnis $JBOSS_HOME/common/lib kopiert. Wir haben dabei auf die log4j-1.2.8.jar verzichtet, da im $JBOSS_HOME/common/lib bereits eine log4j.jar existierte. IronTrack funktionierte damit auch.
Die Datei spy.properties wird nach $JBOSS_HOME/server/default/conf kopiert.
DataSource anpassen
Im JBoss wird die DataSource in der Datei oracle-ds.xml definiert:
<local-tx-datasource>
<jndi-name>db.prod</jndi-name>
<use-java-context>false</use-java-context>
<connection-url>
jdbc:oracle:thin:@db.company.corp:1521:DEV4711
</connection-url>
<driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
<user-name>SCOTT</user-name>
<password>TIGER</password>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter
</exception-sorter-class-name>
</local-tx-datasource>
Wir ändern diese Definition nun so, dass nicht mehr direkt der Oracle-Treiber verwendet wird. Stattdessen tragen wir den Treiber von IronTrack ein und setzen das Präfix p6spy: vor die vorhandene JDBC-URL.
<local-tx-datasource>
<jndi-name>db.prod</jndi-name>
<use-java-context>false</use-java-context>
<connection-url>
p6spy:jdbc:oracle:thin:@db.company.corp:1521:DEV4711
</connection-url>
<driver-class>com.p6spy.engine.spy.P6SpyDriver</driver-class>
<user-name>SCOTT</user-name>
<password>TIGER</password>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter
</exception-sorter-class-name>
</local-tx-datasource>
spy.properties
In dieser Datei wird nun wiederum der Treiber der tatsächlich genutzen Datenbank, in unserem Fall Oracle, eingetragen:
# oracle driver
realdriver=oracle.jdbc.driver.OracleDriver
Desweiteren stellen wir useprefix auf true:
useprefix=true
Bei Bedarf passen wir noch den Monitorport an, über den die GUI das Profiling durchführt:
monitorport=2000
Falls wir auf einen entfernten JBoss zugreifen, ist dies auch der Port, der auf dem entfernten Server nach außen freigeschaltet werden muss.
Über diese Property:
logfile=../log/spy.log
… gibt man Dateinamen und Pfad für die Logdatei an. Nennt man nur den Dateinamen ohne Verzeichnis, landet die Logdatei in $JBOSS_HOME/bin. Diese Logdatei wird sehr schnell sehr groß, weswegen wir von einem Profiling auf einem entfernten Server ausdrücklich abraten.
Profiling
Profiling sollte grundsätzlich immer in einer durch den Entwickler allein kontrollierten Umgebung stattfinden. Also entweder auf einem Server, der exklusiv den Entwicklern vorbehalten ist oder auf dem lokalen Entwicklerrechner. Nur so kann man sicher sein, dass die eigenen Messungen nicht durch unerwartete Fremdeinwirkungen verfälscht werden.
Nun starten wir den JBoss neu und behalten dabei das Server-Logfile $JBOSS_HOME/server/default/log/server.log im Auge, um auf eventuelle Fehler beim Hochfahren zu achten.
Parallel dazu starten wir IronTrack. Nachdem wir vorher schon den Installer ausgeführt haben, sollte sich eine entsprechende Verknüpfung im Startmenü finden. Wir drücken auf die Schaltfläche Connect und geben als Host localhost und den von uns konfigurierten Port 2000 ein.
Wenn bereits SQL-Anfragen gegen den Server laufen, wird sich dies hier live mitverfolgen lassen. Für jede Anfrage wird gezeigt, wie oft sie ausgeführt wurde, wie viele Ergebnisse sie minimal, maximal und im Mittel lieferte, usw.
Sofern man Hibernate einsetzt, lassen sich mit der Property
hibernate.use_sql_comments=true
automatische Debugging-Kommentare aktivieren. Damit wird bei jeder durch Hibernate ausgelösten Query angezeigt, ob es sich um eine Named-Query handelt, und wenn ja, um welche. Andere, dynamisch durch Hibernate generierte Queries, werden ebenfalls deutlich gekennzeichnet.
Fazit
Mit den Angaben aus IronTrack lassen sich sehr schnell die Datenbank-Queries ausfindig machen, die potentielle Performance-Killer sind. Anfragen mit übermäßig langen Laufzeiten, zu großen Ergebnismengen oder sich ständig wiederholende Queries werden sofort sichtbar.
Mit diesen Informationen lassen sich gezielt Performance-Optimierungen, wie z.B. Caching oder Query-Optimierungen, an den notwendigen Stellen vornehmen.
Download und Lizenz
IronTrack SQL wurde unter der freien Apache Software License 1.1 veröffentlicht. Da die Entwickler-Seite von IronTrack nicht mehr existiert, bieten wir IronTrack in unserem Blog direkt zum Download an.
Literatur
Zum Schluss möchte ich an dieser Stelle noch eine Literaturempfehlung aussprechen. Das Buch Performante Webanwendungen: Client- und serverseitige Techniken zur Performance-Optimierung von Daniel Kuhn und Michael Raith beschäftigt sich intensiv mit dem Thema Performance-Optimierung und hat mir bei meiner Arbeit sehr geholfen. Die dort vorgestellten Konzepte helfen bei einer Vielzahl von Problemen und nicht nur bei Webanwendungen.
Das Buch „Performante Webanwendungen: Client- und serverseitige Techniken zur Performance-Optimierung“ von Daniel Kuhn und Michael Raith wird im nächsten Hamburg Web Performance Meetup verlost.
http://www.meetup.com/Hamburg-Web-Performance-Group/events/134685512/
Über die PHP User Group kann man noch einen freien Platz bekommen:
http://www.meetup.com/phpughh/events/127445192/
Hallo, erzählst Du darüber auch etwas auf der DC13?
Ja, habe gerade noch mal zwei Folien dazu eingefügt.