Performance Tuning bei komplexen Domainmodellen

Werbung
Performance Tuning
bei komplexen
Domainmodellen
Christian Dedek
Falk Sippach
Orientation in Objects GmbH
Weinheimer Str. 68
68309 Mannheim
Version: 1.1
www.oio.de
[email protected]
Java, XML und Open Source seit 1998
) Projekte )
• Schlüsselfertige Realisierung
von Software
• Unterstützung laufender
Projekte
• Pilot- und Migrationsprojekte
© 2008 Orientation in Objects GmbH
) Beratung )
) Akademie )
• Methoden, Standards und
• Schulungen, Coaching,
Tools für die Entwicklung
von offenen, unternehmensweiten Systemen
Weiterbildungsberatung,
Train & Solve-Programme
Performance Tuning bei komplexen Domainmodellen
2
1
Performance?
"You need the computing power of a Pentium,
16 MB RAM and 1 GB Harddisk to run Win95.
It took the computing power of
3 Commodore 64 (C64) to fly to the Moon.
Something is wrong here, and it wasn't the Apollo."
Autor unbekannt
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
3
Performance Tuning bei komplexen Domainmodellen
4
Agenda
•
•
•
•
•
•
Problemstellung
Navigation in Objektnetzen
Caching
Veränderung von Objektnetzen
Diverses
Lessons learned
© 2008 Orientation in Objects GmbH
2
Hibernate ist ein "einfaches"
Persistenzframework
<<Tabelle>>
Person
Collection
1
Person
n
PERSON_ID<<PK>>
FIRSTNAME
....
Adresse
Adresse
Adresse
Adresse
<<Tabelle>>
Adresse
session.save(person);
...
person = session.load(Person.class, 1L);
for (Adresse a : person.getAdressen) {
...
}
ADRESSE_ID<<PK>>
PERSON_ID<<FK>>
STRASSE
...
Performance Tuning bei komplexen Domainmodellen
© 2008 Orientation in Objects GmbH
5
Was ist bei komplexen Domänenmodellen?
Entität
Beleg
Collection
Gruppen
Positionen
G1
G2
Positionen
P11
© 2008 Orientation in Objects GmbH
P12
Positionen
P21
P101
P102
Performance Tuning bei komplexen Domainmodellen
6
3
Performance-Probleme mit Hibernate ?
• Hibernate verursacht natürlich Overhead
– durch OR-Mapping, Dirty-Checking, DB-Unabhängigkeit, ...
• Hibernate bringt auch Vorteile: z. B. Caches
– aber ggf. nutzlos durch falsche Verwendung
• Was tun?
– Optimierungsmöglichkeiten von Hibernate ausnutzen
– Stored Procedures oder direkt SQL aus Hibernate aufrufen (DB
spezifische Abfrage-Optimierung)
– Alternativen zu Hibernate: JDBC, iBatis, ...
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
7
Vorgehensweise Performance-Tuning
• Durchführung von Last- und Performanztests
• Testszenarien (aus Use Cases) und deren Qualitätsziele festlegen
– sinnvolle Testdaten (wenn möglich auch Massendaten für Lasttests)
• Problem Testdatenbeschaffung und -reproduktion
– Testszenarien sollten mit vertretbarem Aufwand wiederholbar sein
– ev. Definition von Key Performance Indikator
• Testläufe müssen reproduzierbar sein
– vor Performance-Tuning muß das mehrfache Ausführen eines
Testlaufs gleiche oder zumindest ähnliche Ergebnisse liefern
• Scheduling, Netzwerk...
• kleine Performance-Iterationen
– ein spezielles Tuning und danach Testlauf um Effekt zu erkennen
• Einsatz spezialisierter Werkzeuge
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
8
4
Aktivitäten bei der Testdurchführung
Zielbestimmungen und Mengengerüst festlegen
Testumgebung und Rahmenbedingungen erfassen
Testplan festlegen
Maßnahmen durchführen
Testszenarien festlegen
Test durchführen
[gewichtiger Fehler]
Analyse durchführen
[nicht erfolgreich]
[nicht aussagekräftig]
[erfolgreich]
Misserfolg analysieren
[behebbar]
[nicht behebbar]
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
9
Lasttesttreiber - The Grinder 3
helloWorldService.py
from
from
from
from
net.grinder.script.Grinder import grinder
net.grinder.script import Test
examples.webservices.basic.javaclass import HelloWorld_Impl
java.lang import System
System.setProperty( "javax.xml.rpc.ServiceFactory",
"weblogic.webservice.core.rpc.ServiceFactoryImpl")
webService = HelloWorld_Impl("http://localhost:7001/basic_javaclass/HelloWorld?WSDL")
port = webService.getHelloWorldPort()
portTest = Test(1, "JAXP Port test").wrap(port)
class TestRunner:
def __call__(self):
result = portTest.sayHello(grinder.threadID, grinder.grinderID)
grinder.logger.output("Got '%s'" % result)
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
10
5
Lasttestanalysen durchführen
logs
skript1
data_xxx.log
Analyseunterstützung
error_xxx.log
skript2
Skript
Anzahl Instanzen
Grinder-Import
Speichern als PNG
Anzahl Testläufe
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
11
Werkzeuge - Monitoring Tools
• Profiler: z. B. JProfiler, JProbe, PerformaSure
• JMX-Tooling: z. B. JConsole, AdventNet, MC4J, ...
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
12
6
Hibernate Statistics:
JConsole, Statsviewer
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="Hibernate:name=statistics">
<ref local="statisticsBean" />
</entry>
</map>
</property>
</bean>
<bean id="statisticsBean" class="org.hibernate.jmx.StatisticsService">
<property name="statisticsEnabled">
<value>true</value>
</property>
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
13
Werkzeuge - DB-Analyzer
• Tracer: z. B. P6Spy, IronTrack SQL, Elvyx
• SQL-Clients: z. B. Toad, SQL-Developer (für Oracle DB)
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
14
7
Live-Demo
• Anwendung steht für mehrere Minuten
• Ermittlung der Ursache per P6Spy und IronTrack SQL
– eine bestimmte DB-Abfrage dauert sehr lange
• per SQL-Tool (Explain-Plan, Autotrace)
<<Tabelle>>
Tabelle1
• 1000 Einträge aus Tabelle1 löschen
ID <<PK>>
....
– "delete from Tabelle1 where ..."
– Full Table Scan in Tabelle2 (Constraint-Überprüfung)
• Ursache: Index auf TABELLE1_FK-Spalte fehlt
<<Tabelle>>
Tabelle2
ID <<PK>>
TABELLE1_FK <<FK>>
...
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
15
Autotrace-Auswertung in SQL-Tool:
Optimierung durch Einführung von DB-Indizes
• ohne Index
• mit Index
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
16
8
Agenda
•
•
•
•
•
•
Problemstellung
Navigation in Objektnetzen
Caching
Veränderung von Objektnetzen
Diverses
Lessons learned
Performance Tuning bei komplexen Domainmodellen
© 2008 Orientation in Objects GmbH
17
„Hibernate in 30 Sekunden“
Java Compiler
*.class
Java Virtual Machine
*.hbm.xml
Hibernate
DB
© 2008 Orientation in Objects GmbH
hibernate.cfg.xml
Performance Tuning bei komplexen Domainmodellen
18
9
Schichtentrennung
Business Layer
Interceptor
UserType
SessionFactory
Persistence Layer
Session
Transaction
JNDI
Configuration
Query
JDBC
JTA
Performance Tuning bei komplexen Domainmodellen
© 2008 Orientation in Objects GmbH
19
Optimierte Navigation in komplexen
Objektnetzen/Relationen ?
Mannheim
Heidelberg
<<Tabelle>>
Person
GreenSupply
PERSON_ID<<PK>>
FIRSTNAME
....
G7/2
Hauptstrasse 174
id
strasse
© 2008 Orientation in Objects GmbH
position
<<Tabelle>>
Adresse
ID<<PK>><<FK>>
STRASSE
...
plz
Performance Tuning bei komplexen Domainmodellen
20
10
Relationen navigieren
• Navigationsgeschwindigkeit optimieren
– vollständiges Objektnetz in Speicher laden
– komplexe Netze brauchen viel Speicher
• Speicherverbrauch optimieren
– Relationen werden bei Bedarf nachgeladen
– sog. N+1 Problem
• mögliche Lösungen
–
–
–
–
–
Batch Fetching
Subselect Fetching
Join Fetching (Achtung: Karthesisches Produkt)
HQL
Filter
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
21
N+1 Problem
List<Person> allPersons = session.createQuery("from Person").list();
// List<Person> allPersons = session.createCriteria(Person.class).list();
Map<Person, Address> highestAddresss = new HashMap<Person, Address>();
for (Person person : allPersons) {
Address highestAddress = null;
for (Address address : person.getAddresss() ) { // Initialize the coll.
if (highestAddress == null)
highestAddress = address;
if (address.getPLZ() > highestAddress.getPLZ())
highestAddress = address;
}
highestAddresses.put(person, highestAddress);
}
1 select für Liste der Entitäten
+ n select für jede navigierte Relation
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
22
11
Batch-Fetching
<set name="Addresss" inverse="true" batch-size="10">
<key column="Person_ID"/>
<one-to-many class="Address"/>
</set>
1 select für Liste der Entitäten
select Persons...
+ n/batchsize selects für jede Gruppe navigierter Relationen
select a.* from Address a where a.Person_ID in (?<,?>)
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
23
Laden mit Subselects
<set name="Addresss" inverse="true" fetch="subselect">
<key column="Person_ID"/>
<one-to-many class="Address"/>
</set>
1 select für Liste der Entitäten
select Persons...
+ 1 select für alle navigierte Relationen
select a.* from Address a
where a.Person_ID in (select p.Person_ID from Person p)
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
24
12
Laden mit joins
•Fetchplan
<set name="addresses" inverse="true" fetch="join">
<key column="Person_ID"/>
<one-to-many class="Address"/>
</set>
1 select für Liste der Entitäten mit allen navigierbaren Relationen
select p.*, a.*
from Person p
left outer join Address a on p.Person_ID = a.Person_ID
•besonders interessant für n-1-Relation
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
25
Laden mit expliziten Queries
Alternative Abfrage für eine Liste der Entitäten mit allen navigierbaren
Relationen in spezifischem Anwendungsszenario
List<Person> allPersons =
session.createQuery("from Person p left join fetch p.Addresss").list();
List<Person> allPersons = session.createCriteria(Person.class)
.setFetchMode("addresses", FetchMode.JOIN)
.list();
// Iterate through the collections...
Es resultiert eine Datenbankanfrage
select p.*, a.*
from Person p
left outer join Address a on p.Person_ID = a.Person_ID
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
26
13
Kartesische Produkte
id
name
Bewoh.. Fla.. id
name
leistung satz id
© 2008 Orientation in Objects GmbH
name
akti
vorname
Performance Tuning bei komplexen Domainmodellen
27
Kartesische Produkte
• mit jeder Relation potenziert sich die Größe des resultierenden
Anfrageergebnisses
– DB-Server
• Abfragezeit
• IO-Aufwand
– Applikation
• Speicherverbrauch
• Mappingaufwand in Hibernate
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
28
14
Filter
• Mapping
<class name=“City" table=“KA_STADT" lazy="false">
..
<set name=“dezernenten“
table=“KA_DEZERNENT“ cascade="all,delete-orphan" lazy="false">
<key foreign-key="FK_KA_DEZERNENTEN“
column=“KA_STADT_ID" not-null="true" />
<one-to-many class="de.ex.Dezernent" />
<filter name="limitbyParty “ condition=“PARTY_NAME = :partId"/>
</set>
..
</class>
• Anwendung
getHibernateTemplate().enableFilter("limitByParty").setParameter(“partId"
,“DIE GRAUEN“);..
getHibernateTemplate().getSessionFactory().getCurrentSession().disableFilter
("limitbyParty");
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
29
Feintechniken
• Value types
– Komponente im Kompositum (fehlender Lebenszyklus)
• extra Lazy Proxy Collection
– ev. nützlich bei sehr großen Assoziationsmengen
• Lazy Attribute Fetching
– bei LOB-Feldern bereits implizit
• Interception statt Proxies
– Aufwand eigenimplementierter Lösungen?
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
30
15
Feintuning
• zu komplexe DB-Anfragen
– DB-spezifische Optimierung der execution plans
– Minimierung von join-fetches
• zu viele DB-Anfragen
– fetch-Typen definieren
• eher an der Abfrage als global
• Batchsizes an Verarbeitungsgruppen(Screens) orientieren
– Alternative - Caching erwägen ?
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
31
Optimierungsstrategie
• Ausgangspunkt: Lazy Default-Fetch-Plan
– n-1/1-1-Relationen mit lazy=false
• dann: Szenarien bezogenes Aufzeichnen
• der auslösenden Hibernateanfragen
• der resultierenden DB-anfragen
• daraus: Optimierung der Zahl und Komplexität der resultierenden
DB-Anfragen durch Anpassung der Fetchstrategie der initiierten
Hibernateanfragen
– spezifische Optimierung einer Anfrage
– seltener Optimierung des globalen Fetchplans
• Vorsicht Kostenfalle: manuelle Testausführung
– globale Fetchplanänderungen erfordern Regressionstest
– Lernkurve beachten
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
32
16
bekannte Architektur Muster
• Open Session in View Pattern
– Navigation nutzt Sessioncache
• aber nutzt globale Fetchoptimierung(side Effects ?)
– Query wirkt nicht auf Session Cache
• Vorteil optimierter spezifischer Fetchplan
• spezifische Service Fassade
– Ausgangspunkt Navigation über Session
– Optimierung über spez. Finder in DAO
– DAO-Schnittstelle wird breiter/Wartungsaufwand
• generisches DAO (Preload Pattern JavaMagazin 4/08)
– schmale Finder-Schnittstelle
– keine spezifischer Fetch-Plan
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
33
Performance Tuning bei komplexen Domainmodellen
34
Agenda
•
•
•
•
•
•
Problemstellung
Navigation in Objektnetzen
Caching
Veränderung von Objektnetzen
Diverses
Lessons learned
© 2008 Orientation in Objects GmbH
17
Live Demo: Hibernate Statistics
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
35
Caches in Hibernate
• First-Level:
–
–
–
–
immer aktiviert
nur solange die eine Session offen ist
funktioniert nur bei Aufruf von load/get und bei Assoziationen-Fetch
funktioniert nicht bei Queries
• Second-Level:
– muß erst aktiviert werden
– Konfiguration nicht trivial
– Query-Cache muß separat aktiviert werden
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
36
18
Cache-Konfiguration
• in Hibernate-Settings aktivieren
– CacheProvider (EHCache, OSCache, SwarmCache, TreeCache)
– use_second_level_cache=true
• Cache Regions (angeben für Klassen, Collections oder Queries)
– Usecase spezifisch optimieren
– usage: Caching Strategie
•
•
•
•
read-only:beste Performance
nonstrict-read-write: nur für nicht konkurrierende Zugriffe
read-write: gewährleistet read-commited
transactional: nur bei JTA-Umgebungen
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
37
Gefahren bei Second Level Caches
• andere Applikationen, welche die DB ändern
– Cache muß regelmäßig validiert werden
• zu viele schreibende Zugriffe
– Cache-Miss größer als Cache-Hit: schlechtes Cache-Ratio
• zu kleine Dimensionierung des Cache
– sollte aber auch nicht zu groß dimensioniert werden (GC dauert
länger, längere Validierungsphase mit DB)
Performance kann sogar sinken (durch hohen Verwaltungsaufwand).
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
38
19
Problem: fehlender Cache-Hit
• Beobachtung: Session Cache arbeitet nicht richtig
– immer wieder die gleichen SQL-Selects im Log-Output
• Ursache: statt mit load/get wird mit HQL-Findern gearbeitet
– von AndroMDA generierter Code arbeitet mit findById
– Bug mittlerweile gefixed: AndroMDA generiert jetzt session.get()
•
Alternative für finder: Query-Cache einschalten
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
39
Query-Cache
• Query-Cache überhaupt erstmal einschalten
<prop key="hibernate.cache.use_query_cache">true</prop>
• Query-Cache speichert nur IDs
– muß mit Entity-Cache zusammen arbeiten
• nur sinnvoll für häufige Abfragen mit immer gleichen Parametern
• darum werden Queries defaultmäßig nicht gecached
– setCacheable(true) aufrufen!
public Object getObjectByName(String name) {
Query q = session.createQuery("from Object where name = ?");
q.setParameter(0, name);
q.setCacheable(true);
return q.uniqueResult();
}
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
40
20
Unwirksamer Cache
• z. B. bei Abfragen mit ständig wechselnden Parametern
hql = "from de.oio.Firma ... where validFrom <= :date and
validTo >= :date";
Query q = session.createQuery(hql);
for(..) {
q.setDate(..);
q.list();
}
• ggf. eigene Caches implementieren
– insbesondere wenn immer der gleiche Datensatz geholt wird
– dazu alle abzufragenden Datensätze laden und in Java vergleichen
• funktioniert nur bei überschaubarer Anzahl von Datensätzen!
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
41
Performance Tuning bei komplexen Domainmodellen
42
Agenda
•
•
•
•
•
•
Problemstellung
Navigation in Objektnetzen
Caching
Veränderung von Objektnetzen
Diverses
Lessons learned
© 2008 Orientation in Objects GmbH
21
Collections
• Arten
– Indizierte collections
• maps/lists/arrays über eine index Spalte
– Sets
• Uniqueness
– Bags
• keine Garantien zu Reihenfolge oder Uniqueness
• Id-bag
• TODO Visuell
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
43
Performance Tuning bei komplexen Domainmodellen
44
Flushing-Probleme: Vorher
© 2008 Orientation in Objects GmbH
22
Hintergrund
• Hibernate Session:
– 1st Level Cache, muß mit DB synchronisiert werden -> Flushing
• Flushing:
– Session.flush()
– Transaction.commit()
– bei DB-Abfragen (Dirty Check)
• Dirty Check:
– Objektänderungen so lange wie möglich in der Session vorgehalten
– bei Abfragen ggf. zuerst aufgelaufene Änderungen wegschreiben
– Änderungen werden ermittelt und DML-Anweisungen generiert
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
45
Probleme
• je mehr Daten in der Session, desto länger dauert Dirty Check
• Flush aber oftmals gar nicht notwendig
• Lösungen:
–
–
–
–
Operationen neu ordnen
Objekte aus Session abhängen (read-only)
mit dem Flush warten bis zum Commit (write behind)
Anwendung kontrolliert explizit Flushing
• Default Flushing Verhalten ändern:
– MANUAL, COMMIT, AUTO, ALWAYS
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
46
23
Nachher: Flushmode.COMMIT
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
47
Massendaten-Verarbeitung:
1000 Datensätze löschen
for (...) {
Entity e = session.load(Entity.class, id);
session.delete(e);
}
2000 SQL-Anweisungen
Session-Cache wird unnütz befüllt
eine SQL-Anweisung
minimale DB-Kommunikation
String hql = "delete from Entity where id
between ...";
session.createQuery(hql).execute();
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
48
24
Single SQL statement
• Objekte können verarbeitet werden, ohne sie vorher in Speicher
zu laden (Hibernate unterstützt INSERT/UPDATE/DELETE)
– update Person set gehalt = :newGehalt where status = 'Chef'
• separates Löschen von vielen Elementen ist ineffizient
– session.delete()
– Vorsicht: Springs HibernateTemplate.deleteAll(Collection col) iteriert
über Collection und löscht jedes Element einzeln
• Collection-Mapping Delete-Optimierung
– Hibernate erzeugt einzelnes DELETE bei Collection.clear()
– funktioniert nicht mit inverse="true" (bidirektionalen Beziehungen)
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
49
Stateless Session
sessionFactory.openStatelessSession()
• ideal für Ausführung von Bulk/Batch Operationen (funktioniert
auch mit detached Objects)
• ähnlich einer normalen Session, aber
–
–
–
–
kein Persistenz-Kontext, kein Cache (weder 1st noch 2nd)
kein automatisches Dirty Checking oder transaktionales Write Behind
kein kaskadierendes Verhalten, ignoriert Collections
umgeht Event-Modell und Interceptoren
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
50
25
DB Performance Tuning
• DB Administratoren fragen
• SQL-Dialect nach herstellerspezifische Features untersuchen
– ggf. eigenen Dialekt schreiben
• DB-Indizes
–
–
–
–
fehlen meist bei Grüne-Wiesen-Projekten
DB generiert typischerweise nur Unique-Constraints (PK, ...)
FK-Felder sollten Index erhalten, wenn Sie oft abgefragt werden
aber:
• nicht zu viele Indizes sonst leidet Insert/Update Performance
• Indizes immer überprüfen, ob sie überhaupt verwendet werden
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
51
Hibernate Indizes
• Hibernate unterstützt Index-Definition in Mapping-Files
• für Properties und Assoziationsenden
<property name=".." index="idx" />
<many-to-one name=".." index="fk_idx" />
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
52
26
Agenda
•
•
•
•
•
•
Problemstellung
Navigation in Objektnetzen
Caching
Veränderung von Objektnetzen
Diverses
Lessons learned
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
53
Probleme bei Rich-Client Architekturen
• leider oft: feingranulare Services
– CRUD-Schnittstelle für jede Domain-Klasse (auch für jedes Kind)
– viele Aufrufe an Backend (Netzwerkverkehr)
• bei Objektnetzen hängt teilweise der ganze Objektbaum dran
– Speicherprobleme bei falschem oder fehlendem Umhängen der
Abhängigkeiten (besonders bei bidirektionalen Verbindungen)
• besser: grobgranulare Fassaden
– Usecase-spezifisch
– Minimierung der Aufrufe ans Backend
– Verringerung der Memory-Spitzen durch weniger RMI-Kopien
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
54
27
C2 wird ans Backend geschickt und dann in
Collection Children ausgetauscht
vorher:
Parent
C1
C2
nachher:
service.method(C2)
Children
IN
OUT
Parent
Parent_1
Children
Children_1
C1
C1_1
C2
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
55
Herausgelöste Objekt-Teilgraphen
• Speicher läuft voll bei Remote-Kommunikation
– durch RMI erhalten wir mehrere Objekte im Speicher mit gleicher
Datenbank-Identität
– diese "Kopien" enthalten ggf. wieder den kompletten (kopierten)
Objektgraphen, je nach globaler Fetching-Strategie
• GC kann Speicher nicht freiräumen, wenn noch Referenzen auf
Kopien des Objektgraphen bestehen
– z. B. durch falsches Setzen der bidirektionale Beziehungen
– Workaround für bidirektionale Beziehungen:
addChild(Child child) {
this.getChildren().add(child);
child.setParent(this);
}
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
56
28
Probleme Hibernate Interceptor
public interface Interceptor {
public boolean onLoad(..) throws CallbackException;
public boolean onFlushDirty(..) throws CallbackException;
boolean onSave(..) throws CallbackException;
public void onDelete(..) throws CallbackException;
[..]
public void postFlush(Iterator entities) throws Callba..;
public void afterTransactionCompletion(Transaction tx);
Aufräumen des Interceptor: afterTransactionCompletion()
Aber: Aufruf nur bei Hibernate-Transaktionen, nicht bei JTA
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
57
ThreadLocal bei Hibernate Interceptor
• ThreadLocal-Variable muß immer aufgeräumt werden
– ThreadLocal.remove();
– ThreadLocal kann sonst Memory-Leaks verursachen
• Verwendung eines ThreadLocals im Hibernate Interceptor
– bei Nicht-Hibernate-Transaktionen wird nicht aufgeräumt
– ThreadLocal-Objekt bleibt also bei einer Exception im Speicher
– gefixed ab Hibernate 3.2.6:
• es wird nun immer implizit eine Hibernate-Transaktion gestartet
• dadurch wird Interceptor korrekt deinitialisiert
• Spring-Workaround für ältere Hibernate-Versionen:
– AOP-Throw-Advice für Service-Aufrufe, der Interceptor aufräumt
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
58
29
Garbage Collector Aufwand optimieren
• Genutzten Speicher minimieren
– Speicher ist zwar immer billiger aber weiterhin begrenzt
• z.B. ineffizientes caching führt zu erhöhtem Bedarf an Garbage
Collections
– Caching ist kein High-level-Fix für Probleme tieferer Schichte
– explizite Eviction an der SessionFactory als manueller Eingriffspunkt
im API
• Bessere GC-algorithmen
– hilft bei „typischen Verfügbarkeitsproblemen“
• Phänomen seit Jahrzehnten bei GC-Sprachen bekannt
– paralleler GC-algorithmus auf multi-prozessor systemen
– schwierig (aber notwendig) zu testen
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
59
Spring Bugs
• http://jira.springframework.org/browse/SPR-1690
– falsche Errorcodes für Deadlocks in DB
• http://jira.springframework.org/browse/SPR-2888
– Deadlock bei spezieller init
– Deadlock beim Exceptionhandling von Connections
• http://jira.springframework.org/browse/SPR-3961
– Running benchmarks under high loads with 8 or more concurrents
threads I see significant lock contention from the synchronized block
in
org.springframework.aop.framework.AdvisedSupport.getInterceptorsA
ndDynamicInterceptionAdvice. This is a significant bottleneck in our
benchmarks.
• http://jira.springframework.org/browse/SPR-1968
– wzeite readonly Session in Spring um JSF zu unterstützen
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
60
30
Hibernate Bugs
• http://opensource.atlassian.com/projects/hibernate/browse/HHH2841 Deadlock im Jboss offen
• http://opensource.atlassian.com/projects/hibernate/browse/HHH1669 mögliches Memoryleak
• http://opensource.atlassian.com/projects/hibernate/browse/HB1246 seltener Deadlock wont fix
• Deadlocks in Treibern
– http://opensource.atlassian.com/projects/hibernate/browse/HHH-1167
• Deadlocks in Pools
– http://opensource.atlassian.com/projects/hibernate/browse/HHH-3189
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
61
Performance Tuning bei komplexen Domainmodellen
62
Agenda
•
•
•
•
•
•
Problemstellung
Navigation in Objektnetzen
Caching
Veränderung von Objektnetzen
Diverses
Lessons learned
© 2008 Orientation in Objects GmbH
31
Best Practices I
• Anwendung einer optimistic concurrency zur Implementierung
einer hohen Skalierbarkeit sinnvoll
• Definition einer klaren Sessionmanagement Strategy
– vorteilhaft ist Einbindung in gut dokumentierte Patterns
• Default Fetch Plan für Assoziationen ist lazy
– Optimierung erfolgt gemäß Kapitel 2
– sehr breiter Featureset(Filter,Projektionen,Interceptoren..) zur
Optimierung
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
63
Best Practices II
• Definition der Caching Strategie
– Festlegen welche Bereiche über Navigation (Session Cache) und
welche über Finder (Query Cache optimieren)
– Entity-Cache fein anpassen und tunen
• Verständnis für Implementierungsdetails hilft beim Optimieren
• Definition einer einheitlichen flush-Strategie
– Feintuning: Hibernate auto-flush vs. use case spezifische
Synchronisation
• Untersuchung der GC-Aktivitäten
– Minimierung des GC-Aufwands
– Erkennung (minimaler) Memoryleaks
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
64
32
Nichtfunktionale QM-Strategie
• Performance Meta Antipattern „Performance Afterthoughts“ ist
Realität in der agilen Entwicklung
• nichtfunktionales Qualitätsmanagement benötigt
–
–
–
–
fachlich richtige und realitätsnahe Testfälle
Automatisierung
Entwicklungsbegleitung
Technologische Kompetenz
• Hibernate/Spring
• eingesetztes RDBMS
– Integration ins Entwicklungsteam
• Empfehlung: Definition von Key Performance Indikatoren
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
65
Architekturelle Reife
• Die vorkonfektionierte Grobarchitektur Spring/Hibernate
– hat viele gute Standardeinstellungen in Bezug auf Performanzaspekte
• in beiden Frameworks
– Communities sorgen für Praxisnähe und -einsatz der Ideen
– bietet bei Bedarf sehr viele Möglichkeiten für
Performanzoptimierungen
• oft einfach durch reine Konfiguration
• Leistungsgrenzen der Kombination Spring/Hibernate sind am
technologischen Gesamtstack aus JVM/OS/RDBMS/Netzwerk/IO
angelehnt
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
66
33
Der Kaufmann rechnet - oder Reife vs.
Produktivität
• POJO-Development erhöht Entwicklungsgeschwindigkeit und
senkt den technischen QM-Aufwand
– fast direkte Implementierung fachlicher Modelle möglich
• rasante Entwicklung von Spring/Hibernate/Tooling seit 2003
senkte bisher die Entwicklungsgeschwindigkeit
– sehr hoher Entwicklungsdruck fordert Qualitätsopfer
• Vorteil: Open Source schafft hier Transparenz
– erfordert ständigen KnowHow-Transfer in die Entwicklung
• gerechtfertigt durch Produktivitäts- und Qualitätssteigerungen
– zwingt zu Migrationen der Infrastruktur
• Bsp. MDD-Generatoren, Konfigurations-, Buildmanagement,
Codeanalysewerkzeuge
© 2008 Orientation in Objects GmbH
Performance Tuning bei komplexen Domainmodellen
67
? ? ?
?
?
Fragen ?
Orientation in Objects GmbH
Weinheimer Str. 68
68309 Mannheim
Version: 1.1
www.oio.de
[email protected]
34
Vielen Dank für Ihre
Aufmerksamkeit !
Orientation in Objects GmbH
Weinheimer Str. 68
68309 Mannheim
Version: 1.1
www.oio.de
[email protected]
35
Herunterladen