JAXenter

Das Portal für Java, Architektur, Cloud & Agile

Performanceprobleme? Datenzugriff nicht vergessen

Performance Anti-Patterns – Teil 1

Performanceprobleme? Datenzugriff nicht vergessen

Bei einer auf der JAX 2008 durchgeführten Studie zum Thema Performance nennen beispielsweise 47 Prozent der Befragten das Thema Datenbankzugriffe als Architekturproblemfeld für Performance und Stabilität von Java-Anwendungen, womit dieser Punkt am kritischsten bewertet wurde.

Der einfachste Weg, die Probleme in der Datenbank selbst zu suchen ist sehr oft nicht zielführend, da die wahren Ursachen in der Konzeption der Datenbankzugriffe und des Datenmodells und nicht in schlechter Datenbankkonfiguration zu suchen sind. Im vorliegenden ersten von drei Beiträgen zum Thema Datenbankperformance werden allgemeine Architekturrichtlinien von Datenbankanwendungen behandelt. Die beschriebenen Architekturmuster sollen helfen, eigene Anwendungen richtig zu konzipieren und Performance- und Skalierbarkeitsprobleme bestehender Anwendungen schneller identifizieren zu können. Es sei trotzdem erwähnt, dass auch ein Tuning der Datenbank, beispielsweise das Setzen entsprechender Indizes, immer notwendig ist, um eine gute Performance zu erzielen.

Datenbankanwendungen aus 10.000 Meter

Manchmal hilft ein wenig Abstand, um die Dinge klarer zu sehen (Abb. 1). So ist es auch in der Softwareentwicklung. Werfen wir einmal einen grob granularen Blick auf eine Datenbankanwendung: Grundsätzlich besteht die Anwendung aus drei logischen Schichten - der Datenbank, dem Netzwerk und der Anwendung selbst.

Die Datenbank ist die zentrale Komponente. Eine adequate Tabellenstruktur sowie Konfiguration und das Setzen der notwendigen Indizes sind die Basis performanter Datenbankanwendung.

Das Netzwerk wird dabei sehr häufig vernachlässigt, obwohl es eine zentrale Komponente von Datenbankanwendungen ist. Dies ergibt sich daraus, dass speziell in der Entwicklungsphase Datenbanken lokal installiert werden und somit kaum Latenzzeiten und durch die alleinige Verwendung auch keine Bandbreitenprobleme auftreten. Da das Netzwerk aber eine limitierte Ressource ist, muss es im Auge behalten werden.

Die Anwendung bildet den wichtigsten Teil unserer Betrachtung. Sie steuert alle Zugriffe auf die Daten. Somit mögen sich zwar Probleme an anderer Stelle manifestieren, der Auslöser ist allerdings meistens die Programmlogik. Fehler, die hier gemacht werden, können in den nachfolgenden Schichten nicht mehr kompensiert werden, sondern potenzieren sich dort eher noch.

Datenbankwendungen unter der Lupe

Nachdem wir eine Datenbankanwendungen aus der Vogelperspektive betrachtet haben, wollen wir nun die Details unter die Lupe nehmen und uns ansehen, wie eine typische Datenbankinteraktion abläuft.

Zur Illustration verwenden wir eine Konfiguration, wie sie heute in den meisten Fällen anzutreffen ist. Als Basis dient der JDBC-Layer, dieser stellt uns die Basisfunktionalität für den Datenbankzugriff zur Verfügung - Verbindungsmanagement, Abfragemechanismen und Ergebnisverarbeitung. Die direkte Verwendung der JDBC API ist heute allerdings immer seltener anzutreffen. Meistens wird eine darüber liegende O/R-Mapping-Schicht verwendet, die einerseits für die Umwandlung der tabellarischen Abfrageresultate in Objektmodelle verantwortlich ist, aber auch die Steuerung der JDBC-Schicht übernimmt. Vor allem das Transaktions-Handling, der Verbindungsaufbau und das Absetzen des SQLs wird gekapselt und ist dem Entwickler somit nicht immer direkt transparent. Zusätzlich werden zur Steigerung der Performance sehr oft Caching-Mechanismen verwendet, um den Datenzugriff zu optimieren. In vielen Fällen ist es sogar für sehr erfahrene Entwickler im Umfang mit O/R Mapping Frameworks schwierig, den Zeitpunkt, die Anzahl und den genauen Inhalt der erzeugten SQL-Abfragen vorherzusagen.

Folgen wir also dem Aufrufpfad eines lesenden Datenzugriffs unter Verwendung von Hibernate und eHCache (Abb. 2). Die Anwendung lädt ein Object über den O/R Layer (1). Beim Zugriff wird dann versucht, dieses aus dem Cache zu laden (2). Da der Cache-Zugriff fehlschlägt, wird es über JDBC direkt aus der Datenbank geladen (3) und anschließend im Cache abgelegt (4).

An einer sehr einfachen Datenbanktransaktion sind also sehr viele Komponenten beteiligt. Vieles passiert innernhalb von Frameworks und ist für den Anwendungsentwickler nicht sichtbar. Gerade das Verständnis dieser Details ist aber unbedingt notwendig, um Datenbankzugriffe optimal und somit performant zu implementieren.

Wir können in diesem Fall schon von einem Anti-Pattern sprechen, wenn nicht entsprechende Maßnahmen getroffen werden, um aus der "Blackbox" O/R-Mapper eine Whitebox für den Entwickler zu machen. Eine einfache Möglichkeit besteht darin, das Logging des Frameworks entsprechend zu erhöhen, um die generierten SQL-Statements sichtbar zu machen. Besser ist aber der Einsatz von Profilern oder Monitoring-Lösungen, die nicht nur die Statements, sondern auch die internen Mechanismen des Frameworks sichtbar machen und so erst einen effizienten Einsatz im jeweiligen Anwendungsszenario erlauben.

 
Verwandte Themen: 

Kommentare

Ihr Kommentar zum Thema

Als Gast kommentieren:

Gastkommentare werden nach redaktioneller Prüfung freigegeben (bitte Policy beachten).