Lessons Learned: Java EE Webstack Performance

Post on 18-Dec-2014

577 views 0 download

description

Speaker: Jens Schumann JAX 2013 23.4.2013 Performante Java-EE-6-Webanwendungen? Kein Problem! Doch auch für JSF2/CDI-Anwendungen gilt, dass kleinste Details enorme Auswirkungen haben können. Dies betrifft natürlich stark dynamische Inhalte, insbesondere aber den Einsatz von Ajax und Partial Rendering, EL API 2.2 Features und Composite Components. Worauf man grundsätzlich achten sollte und was unbedingt zu vermeiden ist, zeigt diese Session.

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 ...