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