luni, martie 22, 2010

Optimizarea performantei unei aplicatii Web

Descriu in continuare o serie de unelte (biblioteci Java si tool-uri) folosite in optimizarea performantei pentru o aplicatie Web. Aplicatia are un spatiu limitat de memorie pentru a rula (< 64 M); dupa cateva zile aplicatia cade - Out of memory; aplicatia se incarca greu in browser.


Posibile probleme

1. problema: entitatile sunt folosite si in prezentare si sunt incarcate cu date; solutia: de folosit fetching in mapari - lazy loading pentru colectii in general

In mod implicit prin generare, maparile JPA contin lazy la nivelul colectiilor

2. problema: pe sesiune se pun inutil obiecte; solutie: sa se foloseasca scopul potrivit; daca sunt pe sesiune deja nu se mai pun

La nivel de session ma intreb mai intai daca sub atributul dat exista ceva (!=null); daca da nu fac nimic, daca nu pun valoare sub atribut

Unelte folosite

Glassbox - evidentierea problemelor din runtime

Un tool util in urmarirea aplicatiei in runtime si determinarea punctelor ei slabe in ceea ce priveste performanta. Se instalaeaza in acelasi app server cu aplicatia care se vrea testata si ofera o consola in care sunt logate problemele de performanta care apar. Ofera sugestii pentru rezolvarea lor - destul de utile. Este o aplicatie utila care evidentiaza corect problemele dar nu poate inlocui un profiler.

YSlow - optimizarea paginilor Web

O unealta care concretizeaza experienta acumulata de Yahoo in optimizarea paginilor web. Este un plugin de Firefox care sta alaturi de FireBug si arata ce bune practici sunt incalcate in paginile aplicatiei tale. In general recomandarile sunt: sa se minimizeze numarul de call-uri HTTP prin concatenarea de resurse: javascript, css, introducerea unor atribute in headerul HTTP pentru a se face cache la nivel de proxy, etc. Ofera chiar tool-uri care te pot ajuta in fixarea acestor proble. A fosst nevoie si deun filtro pentru a modifica Expire date pentru resursele statice.

JProfiler - profiling

Cel mai bun profiler pe care il stiu - cei care l-au creat au fost foarte inspirati. Arata in mod dinamic memoria HEAP, thread-urile, call-urile de metode si timpul lor de executie, thread-urile, etc. O unealta foarte utila in a vedea ce se intampla in codul aplicatiei tale in runtime. Evidentiaza clasele specifica de J2EE, permite introduerea de filtre doar pe clasele care ne intereseaza (face introspectie pe cele care ne intereseaza).

WAPT - load test tool

Inlocuitor pentru JMeter - loat test tool. Permite inregistrarea unui script care sa fie executat ulterior pe mai multe thread-uri. Poate simula in acest caz mai mullti useri care folosesc aplicatia furnizand astfel datele necesare pentru profiler. Am preferat WAPT in defavoare JMeter pentru usurinta in folosire - JMeter e mai usor de folosit programatic pentru nightly test, etc (inregistrarea scripturilor se face prin activarea unui proxy). WAPT poate fi folosit cu 20 useri pe o periaoda scurta de timp.

OSCache - cache in partea de prezentare

OScache permite cacahe pentru pagini (filtru) sau fragmente (librarie de taguri). Cache-ul se face dupa chei diferite care pot fi incluse in grupuri. Se paote face flush programatic pe keie, pattern de chei, grupuri sau la intreg cache-ul. Stocarea se poate face in file sistem sau in memori. Configurarea intr-un fisier de configurare - filtrul direct in web.xml.

Am preferat cache pe pagini - pagina principala in care sunt aratate toate articolele si cele in care se arata continutul articolelor. Au aparut probleme cu partea de securitate a aplicatiei si cu URL rewrite. Trebuie avut in vedere ca partea de administrare (aflata sub un user autentificat) nu trebuie sa intre in cache - un user nelogat poate vedea o pagina cu informatii disponibila doar userilor autentificati. O buna practica este selectarea foarte clara a paginilor care pot fi introduse in cache. Invalidarea cache-ului se face programatic la nivel de action in momentul in care se adauga un articol sau comentariu. Efectele sunt vizibile cu ochiul liber.

Folosirea de cache la nivel de fragmente de pagini este nefolositoare - as economisi doar timpul necesar randarii tag-urilor JSTL, deoarece call-ul spre /servici/DAO se face din action, care doar redirecteaza spre JSP. La nivel de pagini, cache-ul pot evita call-urile spre baza date in totalite (pana la invalidarea lui).

EHCache - cache la nivel de Hibernate

EHcache este folosit implicit de Hibernate ca cache de level 1 la nivel de Hibernate session. Pentru level 2 la nivel de session factory este nevoie de a configura explicit clasele care se vor cache-ui. Si in acest caz am preferat cache in file system. De asemenea cache-ul la niivel de query-uri trebuie configurat explicit pentru a fi creat. Pentru a verifica procesul de cache trebuie activat loggerul de ehcache. Configurarea de ehcache se face la nivel de fisier de configurare - numit implicit ehcache.xml.

Compass - index pentru search

Index la nivel de Hibernate - prin intermediul lui se indexeaza toate obiectele care sunt persistate (salvate/incarcate) in baza de date, oferind posibilitatea de a raspunde rapid la search-urile din aplicatie fara a mai face query-uri la nivel de baza de date. Clasele care se doresc indexate trebuie marcate (am ales fisiere de configurare pentrua nu introduce adnotari in entitati - prefer sa le generez pe cele de Hibernate de fiecare data cand schimb ceva in tabele). Indexul poate fi regenerat oricand programatic - si se reactualizeaza singur in runtime prin integrarea cu Hibernate. In spate foloseste Lucene pentru indexare - deci se vor face query-uri de tip Lucene pentru regasirea informatiilor.

Log4J

Pentru a verifica functionarea librariilor de cache, Log4J a fost activat si setat pe un nivel corestunzator. De asemenea am preferat sa fac cache in file sistem pentru a urmari efectiv cache-ul.

Alte unelte utile

Eclipse - debug - pentru a verifica daca se fac call-uri in layerele aplicatiei - thread-ul ramane blocat in breackpoint.
Firebug - analiza paginilor web - DOM, trafic, etc
WireShark - analiza traficului de retea - la un nivel foarte detaliat in tot stack-ul TCP-IP
Tomcat - un enviroment destinat numai testarii; in dezvoltare se foloseste Jetty

Solutii finale

- folosire de cache-uri la nivel de prezentare si de persitenta
- optimizarea incarcarii paginilor web generate

Pasi urmatori

Un increase de memorie si mutarea cache-urilor in memory
Optimizare riguroasa la nivelul query-urilor de Hibernate
Pooling - verificarea parametrilor pentru thread pool in app server si connection pool pentru baza de date
Eliminarea servlet filter nefolositi sau maparea lor pe url-uri mai stricte
Eliminarea librariilor inutile din classpath - pentru a evita Permsize exception
Scalabilitate - Teracotta, SpringS tc server