Lessons Learned: Java EE Webstack Performance
-
Upload
open-knowledge-gmbh -
Category
Technology
-
view
577 -
download
0
description
Transcript of Lessons Learned: Java EE Webstack Performance
Lessons Learned Java EE Webstack Performance
Jens Schumann | open knowledge GmbH
Java EE Webstack Performance!
Web Entwicklung aus der Brille eines Java EE Entwicklers!
!
- The Backend-Tier Part -!
Java EE Webstack Performance!
public List<Order> findTodaysOrders(...) { Calender cal = Calender.getInstance(); cal.set(Calendar.HOUR, 0); ... if (LOG.isDebugEnabled()) { // log method request details } List<Order> result = repository.findOrdersByDate(cal.getTime); if (LOG.isDebugEnabled()) { // log result details } return result; }
Java EE Webstack Performance!
public List<Order> findTodaysOrders(...) { Calender cal = Calender.getInstance(); cal.set(Calendar.HOUR, 0); ... if (LOG.isDebugEnabled()) { // log method request details } List<Order> result = repository.findOrdersByDate(cal.getTime); if (LOG.isDebugEnabled()) { // log result details } return result; }
Java EE Webstack Performance!
public List<Order> findTodaysOrders(...) { Calender cal = Calender.getInstance(); cal.set(Calendar.HOUR, 0); ... if (LOG.isDebugEnabled()) { // log method request details } List<Order> result = repository.findOrdersByDate(cal.getTime); if (LOG.isDebugEnabled()) { // log result details } return result; }
Java EE Webstack Performance!
public List<Order> findTodaysOrders(...) { Calender cal = Calender.getInstance(); cal.set(Calendar.HOUR, 0); ... if (LOG.isDebugEnabled()) { // log method request details } List<Order> result = repository.findOrdersByDate(cal.getTime); if (LOG.isDebugEnabled()) { // log result details } return result; }
Java EE Webstack Performance!
Web Entwicklung aus der Brille eines Java EE Entwicklers!
!
- The Web-Tier Part -!
Java EE Webstack Performance!
@Named @SessionScoped public class OrderOverviewBean() { @Inject private OrderService service; private List<Order> orders; @PostConstruct protected void init() { orders = service.findTodaysOrders(...) } }
Java EE Webstack Performance!
@Named @SessionScoped public class OrderOverviewBean() { @Inject private OrderService service; private List<Order> orders; @PostConstruct protected void init() { orders = service.findTodaysOrders(...) } }
Java EE Webstack Performance!
@Named @SessionScoped public class OrderOverviewBean() { @Inject private OrderService service; private List<Order> orders; @PostConstruct protected void init() { orders = service.findTodaysOrders(...) } }
Java EE Webstack Performance!
@Named @SessionScoped public class OrderOverviewBean() { @Inject private OrderService service; private List<Order> orders; @PostConstruct protected void init() { orders = service.findTodaysOrders(...) } }
Java EE Webstack Performance!
Web Entwicklung aus der Brille eines Java EE Entwicklers!
!
- The UI Part -!
Java EE Webstack Performance!
<html> <head> <link ... href="theme.css" /> <link ... href="primefaces.css.jsf" /> <link ... href="fileupload.css.jsf" /> <script ... src="jquery.js.jsf" /> <script ... src="primefaces.js.jsf" /> <script ... src="fileupload.js.jsf" /> </head> <body> <div id="main_navigation"> <a ...><img src="print.png.jsf?ln=img"></a> <a ...><img src="export.png.jsf?ln=img"></a> </div> </body> </html>
Java EE Webstack Performance!
<html> <head> <link ... href="theme.css" /> <link ... href="primefaces.css.jsf" /> <link ... href="fileupload.css.jsf" /> <script ... src="jquery.js.jsf" /> <script ... src="primefaces.js.jsf“ /> <script ... src="fileupload.js.jsf“" /> </head> <body> <div id="main_navigation"> <a ...><img src="print.png.jsf?ln=img"></a> <a ...><img src="export.png.jsf?ln=img"></a> </div> </body> </html>
rendered=“#{bean.value.attr}“
Java EE Webstack Performance!
<html> <head> <link ... href="theme.css" /> <link ... href="primefaces.css.jsf" /> <link ... href="fileupload.css.jsf" /> <script ... src="jquery.js.jsf" /> <script ... src="primefaces.js.jsf" /> <script ... src="fileupload.js.jsf" /> </head> <body> <div id="main_navigation"> <a ...><img src="print.png.jsf?ln=img"></a> <a ...><img src="export.png.jsf?ln=img"></a> </div> </body> </html>
Java EE Webstack Performance!
Agenda • Die üblichen Verdächtigen • Java EE Zutaten • 6 Gänge Menü • Die Summe macht es • 8 Gänge Menü • Diät-Vorschlag: Kalorien-Arithmetik
Die üblichen Verdächtigen!
Die üblichen Verdächtigen!
• „Tuning“ – Netzwerk-Latenz – Transfer-Volumen – Browser Perform.
• HTML Rendering • CSS Rendering • JS Engine
Die üblichen Verdächtigen!
• „Tuning“ – Dynamic vs. Static – Stateful vs.
Stateless – EL vs. Code
Die üblichen Verdächtigen!
• „Tuning“ – Fine vs. Coarse – Backend-Interaktion
– Caches
Die üblichen Verdächtigen!
• „Tuning“ – EIS Interaktion
Java EE Webstack Performance!
Agenda • Die üblichen Verdächtigen • Java EE Zutaten • 6 Gänge Menü • Die Summe macht es • 8 Gänge Menü • Diät-Vorschlag: Kalorien-Arithmetik
Java EE Zutaten!
• JSF 2.0 – Templates – Composites – EL-API 2.2 – Partial Rendering – Partial Submit – Resource Libs
Java EE Zutaten!
• CDI 1.0 – Injection – Conversation – Events
Java EE Zutaten!
• CDI 1.0 – Injection – Events – Scopes
Java EE Zutaten!
• EJB 3.1 – Injection – Asynchronous
Java EE Zutaten!
• EJB 3.1 – Injection – Asynchronous
out of scope
Java EE Zutaten!
• CDI 1.0 – Injection – Events – Scopes
Java EE Zutaten!
• JPA 2.0 – Cache API – Criteria API – Orphaned
Removal – ...
Java EE Zutaten!
• JPA 2.0 – Cache API – Criteria API – Orphaned
Removal – ...
out of scope
Java EE Webstack Performance!
Agenda • Die üblichen Verdächtigen • Java EE Zutaten • 6 Gänge Menü • Die Summe macht es • 8 Gänge Menü • Diät-Vorschlag: Kalorien-Arithmetik
6 Gänge Menu!
6 Gänge Menu!
• Phase I: Restore View – (Wieder-)herstellen des aktionsauslösenden/
angeforderten Views • Erstellung Komponentenbaum auf Basis .xhtml
Seite • Beim ersten Request grundsätzlicher Aufbau des
Komponentenbaums
6 Gänge Menu!
• Restore View: Alles OK*
*JSF Development Mode beachten
6 Gänge Menu!
• Phase II: Apply Requests – Zuweisung (HTTP-Request) Parameter zu
JSF Komponenten als submittedValue • Keine Validierung • Keine Konvertierung
6 Gänge Menu!
• Apply Requests: Alles OK
6 Gänge Menu!
• Phase III: Process Validations – Konvertierung und Validierung der
Eingabeparameter und Berücksichtigung der im Modell und View definierten Regeln
– Nutzung von • JSF-Validatoren • JSF-Konvertern
6 Gänge Menu!
• Process Validations: Workload – Große Formularfelder erfordern hohe Anzahl
an Konvertierung und Validierung • Auswirkungen bei Date, BigDecimal
– Folge: Vergleichsweise hoher Anteil in Validierung bei Submit des gesamten Formulars
6 Gänge Menu!
• Process Validations: Workload
6 Gänge Menu!
• Process Validations: Workload-Tipp – Nutzung von Wizards
• Verkleinerung Formularbestandteile
– Partial Submits für Value Changes • Kein finales Form Submit
6 Gänge Menu!
• Process Validations: PostConstruct – Ein einfaches Registrations-Formular
6 Gänge Menu!
• Process Validations: PostConstruct
6 Gänge Menu!
• Process Validations: PostConstruct-Tipp – Vermischung von Use-Cases vermeiden
• Datenaufbereitung und Form Behandlung sind unterschiedliche Use Cases
– @PostConstruct in @RequestScoped gehören unter besondere Beobachtung
6 Gänge Menu!
@Named @RequestScoped public class RegistrationBean() { private List<News> currentNews; private String firstName; private String lastName; @PostConstruct protected void init() { currentNews = service.getPersonlizedNews(...) } }
6 Gänge Menu!
@Named @RequestScoped public class RegistrationBean() { private List<News> currentNews; private String firstName; private String lastName; @PostConstruct protected void init() { currentNews = service.getPersonlizedNews(...) } }
6 Gänge Menu!
• Process Validations: Backend Integration – Validatoren/Konverter können unter
Umständen JPA Caching Effekte nicht nutzen • Transaction-Bound EntityManager
6 Gänge Menu!
• Process Validations: Backend Integration
6 Gänge Menu!
• Process Validations: Backend-Tipp – RequestScoped EntityManager nutzen* @Produces @RequestScoped @PersistenceContext(unitName=“x", type=EXTENDED) public EntityManager createEntityManager( @PersistenceUnit(unitName = “x") EntityManagerFactory factory) { return factory.createEntityManager(); }
*inclusive Disposer Method
6 Gänge Menu!
• Phase IV: Update Model Values – Aktualisierung des Modells durch Zuweisung
der konvertierten und validierten Parameter
6 Gänge Menu!
• Update Model Values – alles OK
6 Gänge Menu!
• Phase V: Invoke Application – Ausführung der Zielmethode via Reflection
6 Gänge Menu!
• Invoke Application: Keine Auffälligkeiten – Siehe „Die üblichen Verdächtigen“ – Siehe „Die Summe macht es“ – Siehe „PostConstruct“
6 Gänge Menu!
• Phase VI: Render Response – Erzeugung einer (HTML-)Antwort auf der Basis
des berechneten Ziel-Views und Modells • Nutzung von der JSF-Renderer aus dem
verwendeten Renderkit • Entfällt bei redirect
6 Gänge Menu!
• Render View: Komplexe Views – Moderne Web Anwendungen haben oft
Desktop Charakter • Tiefe Verschachtelungen • Bedingte Sichtbarkeiten
6 Gänge Menu!
• Render View: Komplexe Views-Tipp – Unnötige Formatierungsanweisungen
vermeiden – Layout via CSS und nicht via JSF
– Exit-Strategie Client Side Code • JSF Client-Behaviours • Pure JS/JQuery
6 Gänge Menu!
• Render View: Possibly-Lazy Views – Modale Dialoge, Detailansichten und Tabs
gehören zu heutigen Webanwendungen • Desktop Usability
– Darstellung der Inhalte erfolgt In-Page, ohne Neuladen der Seite
– Inhalte werden unter Umständen mit jedem Request ausgeliefert
6 Gänge Menu!
• Render View: Possibly-Lazy Views-Tip – Nicht sichtbare Inhalte auch nicht zum Client
ausliefern • Dynamisches Nachladen realisieren • „Dynamic“ Eigenschaften der Komponenten nutzen
<p:dialog modal="true" dynamic=“true“>...</p:dialog>
6 Gänge Menu!
• Render Response: EL Performance – Performance Reference Implementierung
EL- API ist OK
– JUEL* bringt erheblichen Performance-Gewinn
*http://juel.sourceforge.net
6 Gänge Menu!
• Render Response: EL Graph Evaluation – In der Regel werden trotz eingeführter
„Variablen“ EL Ausdrücke immer komplett ausgewertet
<p:dataTable var=“customer" value="#{customerOverview.customers}“> <p:column> <h:outputText value="#{customer.firstName}"/> </p:column> </p:dataTable>
6 Gänge Menu!
• Render Response: EL Evaluation-TIP – Sehr tiefe EL-Ausdrücke, speziell über
Collections vermeiden – Composite Components mit Backing Beans
verwenden • Binding-Attribute
Java EE Webstack Performance!
Agenda • Die üblichen Verdächtigen • Java EE Zutaten • 6 Gänge Menü • Die Summe macht es • 8 Gänge Menü • Diät-Vorschlag: Kalorien-Arithmetik
Die Summe macht es!
• Verschiedene Probleme werden nur in Kombination relevant – PostConstruct Evil – „Rendered“-Attribute – EL Actions mit Params – CDI Events und Scopes – EntityManager Lifecycle
Die Summe macht es!
• PostConstruct Evil – PostConstruct führt in allen Phase zu
unerwarteten Seiteneffekten
– Tipp (Wiederholung) • Eine CDI Bean pro Use Case • Fachfremde Initialisierung IMMER auslagern • Bei RequestScoped Beans auf Lazy Init statt
PostConstruct Initialisierung ausweichen
Die Summe macht es!
• Rendered-Attribute – Auswertung rendered-EL-Ausdruck erfolgt im
LifeCycle mehrmals (bis zu 6 mal)
– Tipp: Auf EL-Ausführungszeiten achten – Tipp: Rendered und PostConstruct beachten
<h:panelGrid rendered="#{db.welcomeMessages.size() > 0}“ > ... </h:panelGrid>
Die Summe macht es!
• Parameterisierte EL-Actions – EL API 2.2 erlaubt parameterisierte
Methodenaufrufe • EL-API(!) enthält performancerelevante Bug*
– Tipp: EL-API 2.2.2 oder später nutzen
<h:commandButton action="#{delController.delete(customer)}“ ... />
*http://java.net/jira/browse/UEL-19
Die Summe macht es!
• CDI-Events, Scopes und PostConstruct – CDI Events eignen sich für Aktualisierung von
Informationen in der Web Anwendung
public class CustomerService { @Inject @Deleted private Event<Customer> eventSource; public void deleteCustomer(Customer customer) { ... eventSource.fire(customer); } }
Die Summe macht es!
• CDI-Events, Scopes und PostConstruct @Named @SessionScoped public class CustomerService { public void onCustomerDelete(@Observes @Deleted Customer customer) { // reset internal list loadList(); } @PostConstruct public void loadList() { ... } }
Die Summe macht es!
• CDI-Events, Scopes und PostConstruct – Laden/Aufbereitung von Daten in Observer-
Methoden vermeiden – @Observers(notifyObserver=IF_EXISTS)
verwenden
Die Summe macht es!
• CDI-Events, Scopes und PostConstruct @Named @SessionScoped public class CustomerService { private List<Customer> customers; public void onCustomerDelete(@Observes @Deleted Customer customer) { // remove customer from customers list ... } }
Die Summe macht es!
• EntityManager LifeCycle – In der Regel ist der Lebenszyklus an Java EE
EntityManager gebunden • Lebt für den Zeitraum der Transaktion
– Folge: Keine Caching Effekte über alle LifeCycle Phasen hinweg
– Tipp: RequestScoped EntityManager nutzen
Java EE Webstack Performance!
Agenda • Die üblichen Verdächtigen • Java EE Zutaten • 6 Gänge Menü • Die Summe macht es • 8 Gänge Menü • Diät-Vorschlag: Kalorien-Arithmetik
8 Gänge Menü!
8 Gänge Menü!
Client (Browser)
Netzwerk
8 Gänge Menü!
• Partial Rendering / Partial Submits – Partial Submit
• Teilweise Übertragung von Formularinhalten
– Partial Rendering • Aktualisierung von ausgewählten HTML Elementen
8 Gänge Menü!
• Partial Rendering / Partial Submits – Problem Partial Rendering
• Es gilt die Kochanleitung für das 6 Gänge Menü • Partial Rendering kann bei komplexen die Browser
Render-Engine stark belasten – Tiefe Tabellenstrukturen – Modale Dialoge / Lazy
– Tipp: Frühzeitig Auswirkungen im IE 7+ testen
8 Gänge Menü!
• Composite Component Resources – Deklaration von HTML Ressourcen in CC‘s
• CSS, JavaScript, (Images)
– Folge: Zusätzliche Client-Server Kommunikation
<composite:implementation> <h:outputStylesheet library="css" name="errorPopup.css"/> <h:outputScript library="js" name=“errorPopup.js“ target="head"/> </composite:implementation>
8 Gänge Menü!
• Composite Component Resources - Tipp – Bildung von Composite Component Groups mit
shared CSS/JavaScript Libraries
<composite:implementation> <h:outputStylesheet library="css" name=“utility.css"/> <h:outputScript library="js" name=“utility.js“ target="head"/> </composite:implementation>
Java EE Webstack Performance!
Agenda • Die üblichen Verdächtigen • Java EE Zutaten • 6 Gänge Menü • Die Summe macht es • 8 Gänge Menü • Diät-Vorschlag: Kalorien-Arithmetik
Diät-Vorschlag: Kalorien-Arithmetik!
• End-to-End Performance betrachten
• High-Level Monitoring im Echtbetrieb
• Low-Level Analyse On-Demand – Java Profiling – Netzwerk Profiling
Diät-Vorschlag: Kalorien-Arithmetik!
• High-Level Performance Monitoring – JAMON, JavaMelody, Java Simon, JETM, ... – JXInsight, Dynatrace, ...
Gibt es noch Fragen?
Dann los ...