2012. december 17., hétfő

2012-es évértékelő

Lassan vége az évnek, így most eljött az idő egy kis visszatekintésre és összegzésre majd írnék pár gondolatot a jövővel kapcsolatban is.

A 2012-es év nagyon hasznos és eredményes volt a számomra! A blogom olvasói már tudják, hogy részt vettem a Raiffeisen Bank stabilizációs projektében ahol is sikeresen elértük a kitűzött célokat! A stabilizációs projekt egyben a Compuware dynaTrace APM legelső hazai bevetését is jelentette, így a bank lett a magyarországi referencia implementáció. A projekt keretében nemcsak megismertem a banki IT architektúrát és a mindennapi problémákat, hanem néhány eszközt (dynaTrace, Splunk, Eclipse Memory Analyzer, VisualVM, IBM PMAT, IBM HA, IBM TDA) a valós életbeli problémákon keresztül is alkalmazhattam: performancia optimalizálás és stabilitási problémák megoldása, thread és heap dump analizálás valamint memória szivárgások beazonosítása.

Foglalkoztam még kliens oldali optimalizációval is a dynaTrace AJAX segítségével valamint kidolgoztam egy migrációs útvonalat ahhoz, hogy a jelenlegi banki standard Internet Explorer-ről fokozatosan (akár oldalanként) áttérhessenek a Google Chrome használatára. Erről azért még blogolok valamikor...

Mivel a konfigurációs jellegű problémák ellenőrzéséhez és beazonosításához a WebSphere admin konzol kevésnek bizonyult, ezért készítettem egy Jython szkriptet, ami a wsadmin-t felhasználva ki dump-olta egy HTML fájlba a szerver, jms, adatforrás és alkalmazás információkat mint például a heap beállítások, gc policy beállítások, jvm argumentumok, pool beállítások, telepített alkalmazások verziószáma és webservice binding információi, stb... . A szkriptet CRON-al ütemezve és naponta lefuttatva mindig aktuális és gyorsan kereshető információkat szolgáltatott a számunkra.

Miután megismertem a környezetet és a felmerült problémákat, néhány javaslatot is tettem annak érdekében, hogy ne csak foltozgassuk ezeket hanem akadályozzuk meg azt is hogy a jövőben ismételten bekerülhessenek a rendszerbe! A javaslatom a Jenkins és a Sonar banki bevezetését jelentette a forráskódok statikus ellenőrzéséhez! A kódellenőrzéshez kapcsolódóan néhány felmerült problémára PMD alapú kódellenőrző kiegészítőket fejlesztettem valamint segítséget nyújtottam a belsős kollégák számára a projektek bekötéséhez és a további kódellenőrző plugin-ok implementálásához.

A Jenkins és a Sonar banki környezethez való illesztéséhez további ötleteim is megvalósításra kerültek. A Sonar keretrendszerhez fejlesztettem egy JRuby On Rails alapú Sonar plugin-t ami a webes felületén keresztül megvalósította a banki LDAP csoportok leszinkronizálását valamint ajánlásokat adott a projektek és csoportok összerendeléséhez.


A másik ötletem azt a célt szolgálta, hogy a Jenkins alá bekötött és sikeresen build-elhető projekteket egyenként vagy batch módban a homokozó környezetből egy gombnyomásra át lehessen emelni az éles környezetbe. Ehhez a Jenkins platform kiterjesztési pontjait és az Apache Jelly technológiát alkalmaztam egy unix szkripttel kiegészítve.


A stabilizációs projekt az év végére befejeződött, én pedig kaptam egy új munkalehetőséget a Telvice kft-nél, ahol is a dynaTrace magyarországi supportálása ill. ehhez kapcsolódóan szakértői feladataim lesznek. A jövőt tekintve kifejezetten érdekes feladatok várnak rám, ugyanis megismerhetem több nagy hazai cég IT rendszerét és problémáit valamint segíthetek ezek megoldásában. A Java-s fejlesztői és üzemeltetési vonalon maradva pedig tervezem néhány gyártói és Oracle Java-s vizsga letételét is. A blogolást is folytatom, a munkámból adódóan számíthattok még egy-két dynaTrace-es bejegyzésre is de lesz más is bőven.

Ezúton is kellemes ünnepeket kívánok mindenkinek!

2012. október 24., szerda

DynaTrace - A feltárt szerver oldali hibák 2.

Az előző post folytatásaként ismét néhány jellegzetes hibatípust gyűjtöttem össze amelyekkel jómagam foglalkoztam a stabilizációs projekt kapcsán. Hát igen, a DynaTrace ezen hibák megtalálásában is elég hasznosnak bizonyult, nézzük is meg hogy hogyan segített.

Hiányzó TimeOut-ok

Sok helyen találkoztam azzal, hogy a WebService, EJB, URLConnection vagy DB lekérdezéseknél nem voltak timeout-ok definiálva. A timeout-ok hiánya néha komoly stabilitási problémákhoz is vezetett, pl. többször is előfordult, hogy egy belassult web-szolgáltatás miatt a kérések feltorlódtak így a válaszidők is megnövekedtek. Ha már a timeout-okat állítgatjuk, a programozott (java kódbeli) megadás helyett érdemes inkább a konfigurációs paraméterrel való megadást választani, így akár futásidőben is módosíthatjuk az értékét.

Ahogy az alábbi ábra is mutatja, a timeout jellegű hibákat a DynaTrace segítségével elég egyszerűen be lehet azonosítani!


Prepared Statement problémák

Szintén gyakori eset, hogy az SQL lekérdezések paraméterei string konkatenációval voltak beillesztve a PreparedStatement-nél preferált paraméter binding helyett. Ezzel két probléma is van, egyrészt SQL injection-ra adhat lehetőséget másrészt a statement cache-t nem tudjuk majd jól kihasználni.

A lekérdezések végrehajtása alapvetően 2 fázisra osztható az előkészítésre és a paraméterek behelyettesítésével történő végrehajtásra. Az előkészítés egy cpu igényes művelet, ami minden statement legelső végrehajtásakor lefut. Ez a fázis a parszolás, a szintaktikai ellenőrzés és fordítás valalmint a végrehajtási terv elkészítésének a lépéseit tartalmazza. Az előkészített statement, a db connection-onként nyilvántartott statement cache-ben eltárolódik és amíg ebben a cache-ben megtalálható, addig a következő végrehajtások során csak a paramétereket kell behelyettesíteni, az erőforrás igényes előkészítést már nem kell újból végrehajtani.

Nézzünk erre egy példát! Vegyük a "SELECT ID id, DESCRIPTION desc FROM mytable WHERE BL=? ORDER BY desc" lekérdezést, ahol is helyesen a WHERE feltételnél található paraméter nincs beégetve, így ebben a formában a lekérdezés a statement cache-ben csak 1 helyet foglal, függetlenül attól hogy milyen paramétert használunk a lekérdezés során. Az alábbi DynaTrace-el beazonosított SQL lekérdezés pedig a kerülendő változat, miszerint ugyanaz a lekérdezés 8 helyet foglal el a statement cache-ben mivel a paraméter be lett égetve a lekérdezésbe.


Érdemes tudni, hogy a WebSphere alkalmazás szerver alatt a prepared statement cache size alapértelmezett értéke 10, JBoss alatt pedig ha nincs definiálva akkor 0, így ennek az értékét még akkor is érdemes megnövelni ha egyébként paraméterezett sql-eket használtunk!

A statement cache pontos bekonfigurálásához érdemes monitorozást végezni a WebSphere admin console integrált IBM TivoliPerformance Viewer vagy a DynaTrace segítségével a Prepared Statement Cache Discard Count PM-re feliratkozva. Sőt a DynaTrace ezen felül lehetőséget biztosít a parszolás nélkül végrehajtott lekérdezések arányának a monitorozásához is az Executions without parse ratio metrika segítségével.

Java implementációs hibák sokasága

A konfigurációs problémák mellett rengeteg java implementációs hiba is napvilágra került, éppen csak néhány példát megemlítve:

  • Néhány lapozó komponens lekérte az összes rekordot, nemcsak az adott oldalon megjelenítendőket.
  • Explicit garbage collector hívások a Java kódban.
  • Túl gyakori és felesleges Runtime.exec() hívások.
  • Le nem kezelt (és néha a felületre is kijutott) kivételek.
  • Memória szivárgások. (Memory Leak)
  • Custom megoldások implementációs hibái: Saját DB Connection Pool szinkronizációs és logikai hibák.

Ne maradj le a folytatásról sem!


2012. október 8., hétfő

DynaTrace - A feltárt szerver oldali hibák 1.

A stabilizációs projekt során közel 500 hibát sikerült beazonosítanunk és megoldanunk, melyek döntő többsége valamilyen kódolási vagy konfigurációs problémára volt visszavezethető. A következő néhány bejegyzésemben ezekből emelnék ki néhány fontosabbat és írnék a megoldásukról is!

Nem optimális JVM beállítások

Az éles banki környezetben több mint 10 WebSphere klaszter volt kialakítva. A WAS szerverekhez kapcsolódó performancia problémák nyomozásakor találtunk környezetenkénti konfigurációs eltéréseket (melyek megelőzéséről egy későbbi cikkemben fogok írni) valamint nem optimális és hiányzó beállításokat melyekből most csak egyet emelnék ki, mégpedig a JVM Garbage Collector beállításait.

Amikor egy alkalmazás szerveren tranzakcionális jellegű web-alkalmazásokat futtatunk (melyeknél sok a rövid életű objektum), akkor IBM JVM esetén a gencon lesz a nyerő Garbage Collector stratégia! Ennek ellenére a szerverek többségénél nem volt megadva gc policy (alapértelmezett az optthruput) vagy egy másik gc policy volt definiálva, ahol pedig a gencon volt beállítva a nursery terület mérete túl alacsonynak bizonyult, feltehetően nem volt finomhangolva.

Habár a JVM GC tunning a VisualVM eszközzel is megoldható lett volna,  nekünk pont jól jött hogy a DynaTrace is támogatja a JVM monitorozását. A gc suspension time és a heap memória kihasználtság monitorozásához így összedobtunk egy DynaTrace-es dashboard-ot, az optimalizálás során pedig közel 90%-os GC suspension time csökkenést sikerült elérni, ami várakozási időben elég komoly javulást jelentett. (lásd az alábbi ábrákat)


Hiányzó IceFaces konfigurációs paraméterek

A DynaTrace beépített Exceptions nézetét használtuk fel, hogy a keretrendszeri és az alkalmazásokhoz tartozó kivételeket láthatóvá tegyük. Esetünkben a top 20-as listában jópár IceFaces-es kivétel keletkezett, melyek hiányzó web.xml konfigurációs paraméterekre voltak visszavezethetők!


Persze felmerülhet a kérdés, hogy milyen költséges lehet egy kivétel feldobása? Általában elhanyagolható, azonban a fenti esetben ez a kb. 10.000 IceFaces-es kivétel mindössze 10 perc alatt gyűlt össze, így egyértelműen javítani kellett! Amire érdemes odafigyelni, hogy nagy számú kivétel esetén a catch ágban elhelyezett kompenzációs logika valamint a több rétegen keresztül gyűjtögetett stack trace-ek kinaplózása okozhat még jelentősebb performancia problémát!

A folytatás hamarosan következik...



2012. augusztus 21., kedd

Szavazz a Seamplex-re!

Kedves olvasóim!

Amikor elnyertem a 2010-es év legjobb Java fejlesztője díjat, elhatároztam hogy a munkám során felhalmozódott szakmai tapasztalatokat összegyűjtöm és egy saját blog formájában megosztom mindenkivel, így 2011 januárjában útjára indítottam a Seamplex-et! 

A cikkek rendszerint az aktuális feladataimhoz és a projektjeimhez kötődnek, így az elmúlt másfél évben blogoltam néhány hasznos jáva közeli eszközről, tesztelésről és a versenyeimről is. Ez idő alatt több mint 30 cikk született meg, amelyekből a statisztikák alapján a legnépszerűbb bejegyzések a Selenium-os és a banki stabilizációs projekt-el kapcsolatos írásaim voltak.

Persze a blogolás velejárója, hogy a cikkek elkészítésére időt kell fordítani, ugyanis egy-egy cikk megírása sokszor több órát is igénybe vehet. Mivel a bejegyzések elkészítése a szabadidőmben történik, a folytatáshoz mindig ösztönzően hatnak a kommentek és a Ti észrevételeitek. Most azonban adódott  egy lehetőség amivel megtudnátok támogatni a blogomat!

Beneveztem a Seamplex-et a GoldenBlog versenyre, az IT blogok kategóriába! A szavazás augusztus 20-án reggel indul és szeptember 6-án éjfélig tart, szavazni pedig a Facebook-belépéssel lehet. Szóval ha tetszik a blogom és hasznosnak találtad az eddigi írásaimat, szavazz rám mindenféleképpen a versenyen!

Hajrá és köszönök minden szavazatot! 

Balázs. 

2012. július 29., vasárnap

DynaTrace - Performancia problémák monitorozása

A performancia problémák analizálása mellett a DynaTrace kiválóan alkalmas a teljes rendszerünk monitorozására és az incidens alapú riasztások kialakítására is! A mostani bejegyzésben a lehetőségek részletes ismertetése helyett, inkább néhány olyan dashboard-ot fogok bemutatni aminek nagy hasznát vettem a SWAT-os problémák felkutatása során.

Ahhoz, hogy bizonyos jellemzőket (Measure) - pl. processzor kihasználtság, jvm heap használat, válasz idők, stb... - monitorozni tudjunk, fel kell rájuk iratkozni és ezután lehetőségünk van arra hogy a saját készítésű chart-oknál (több chart-ból képzett logikai egység a dashboard), incidens detektálásnál vagy a DynaTrace-es business transaction-oknál hivatkozzunk rájuk. A DynaTrace az alapértelmezett és a kiválasztott measure-ök adatait a Perfromance Warehouse-ban fogja eltárolni. Fontos megjegyezni, hogy ezek az eltárolt adatok csak aggregátumok, azaz a min, max, avg, sum és count értékek tárolódnak el a meghatározott időablakra nézve (10sec, de akár módosítható is a DynaTrace felületén).

Bejelentkező oldali válaszidők

Mivel a bejelentkezési oldal válaszideje eleinte eléggé problémás volt, ezért létrehoztunk egy measure-t a login.jsp válaszidejéhez és készítettünk hozzá 2 chartot amit egy dashboard-ban foglaltunk össze. A felső chart az adott időszakra nézett maximális, átlagos és a minimális válaszidőket tartalmazta az alsó chart pedig a login.jsp -re érkező kérések számát, azaz a terhelést. Amikor azt tapasztaltuk, hogy közel állandó terhelés mellett elkezdtek emelkedni a válaszidők, a dashboard-ról tovább tudtunk fúrni (drill down) az érintett PurePath-okhoz vagy a TransactionFlow-hoz, így gyorsan beazonosítottuk a problémás komponenseket és a megnövekedett válaszidők pontos okát.

 
Összegzett válaszidők alkalmazásonkénti lebontása

Mivel a konténerekben több web-alkalmazás is futott, ezért készítettünk egy olyan dashboard-ot, amivel a válaszidőket alkalmazások szerint lebontva (a web-kontext-root alapján) is tudtuk monitorozni. A lenti dashboard-on is látható, hogy volt néhány alkalmazás ami folyamatosan benne volt a top 5-ben, így az optimalizálást is értelemszerűen ezekkel kezdtük!

 
JMX és PMI alapú measure-ök létrehozása

A DynaTrace arra is ad lehetőséget, hogy a standard JMX-es (pl.:JBoss,Tomcat) vagy a WebSphere által használt PMI-s measure-ökre is feliratkozzunk, így többek között kinyerhetjük az AJP-s CurrentThreadBusy értékét aminek a folyamatos monitorozásáért egy saját készítésű Server Health Dashboard felelt.


Server Health Dashboard

Az alábbi dashboard 12 chart-ból lett összeállítva. Az első sorban, egy klaszterbe kötött 4 szerver-re érkező request-ek száma látható, ami kifejezetten hasznos volt amikor a load balancer-ek félreterhelését vizsgáltuk és egy újabb terhelés kiegyenlítő stratégiát kerestünk. A második sorban a jmx measure-ből kinyert AJP-CurrentThreadBusy értékeinek az alakulása látható a 4 szerver szerint eltérő színnel jelezve. Amikor valamelyik hátérrendszerrel problémák adódtak (pl. szinkronizációs hibák) az AJP-s Thread-ek hirtelen megemelkedése mindig azonnal jelezte a problémát. A harmadik sorban az egyes szerverekhez tartozó heap memória használatát monitoroztuk, ahol egy kis jvm tunning után egyből megjelentek a jól ismert fűrész fogak. A 4. sorban található chart-okkal pedig a szerverekhez tartozó CPU használatot és a request-ek szerverek közötötti eloszlását monitoroztuk.


PurePath-ok csoportosítása a JSESSIONID alapján

A DynaTrace-nek a business transaction koncepciója lehetőséget ad arra, hogy a számunkra fontos PurePath-okra szűrési feltételeket és csoportosításokat fogalmazzunk meg, majd az így kialakított BT-at saját chart-okon jelenítsük meg. Egy ilyen üzleti tranzakció volt a PurePath-ok jsessionid alapján történő csoportosítása, amit az alábbi képernyőkép szerint adhatunk meg a DynaTrace felületén.


A business transaction eredményét táblázatos formában is megtekinthetjük, ahonnan tovább szűrhetünk pl. a PurePathok irányába, így könnyen vissza tudtuk követni, hogy a felhasználók milyen műveleteket hajtottak végre egy-egy munkamenet során.


Az előbb ismertetett business transaction-hoz hasonlóan a HTTP Session userName alapján történő csoportosításhoz is készítettünk egy üzleti tranzakciót, így a help desk számára mindig értékes információkkal tudtunk szolgálni amikor valamelyik felhasználó kéréseit kellett visszakövetni egy adott időintervallumban.

A folytatásban a DynaTrace-el feltárt hibákból szemezgetek néhányat.


2012. június 13., szerda

DynaTrace - Performancia problémák analizálása

A következőkben a performancia problémák analizálásához kapcsolódó dynaTrace-es dashboard-okat fogom bemutatni. Az analizálást sok hasznos feature is segíti, ilyen például a dashboardok közötti átnavigálhatóság, a hotspotok azonnali kijelzése vagy az időablak széleskörű állíthatósága. 

PurePaths

A PurePath-ok minden egyes kérésnek a teljes végrehajtási útvonalát tartalmazzák, (beleértve az RMI, WebService, JMS, EJB hívásokat) kontextus információkkal kiegészítve (naplók, kivételek, metódus argumentumok). Az alábbi példánál a kijelölt PurePath hívási láncán és a jobb oldali HotSpots panelon is könnyen beazonosítható, hogy a teljes végrehajtási időért a validateCreditCardNumber(String,int) metódus volt a felelős! Gondoljunk csak bele, hogy egy nagyobb rendszer esetén ezt mennyi idő lett volna megállapítani a hagyományos módszerek segítségével...


WebRequests

A WebRequests nézetnél megtekinthető, hogy milyen egyedi webes kérések (URI+Query String) érkeztek a kiválasztott időintervallumban. Ahogy a cikk elején említettem innen tovább fúrhatunk bármilyen irányba.


MethodHotspots

A method hotspots nézetből megtudhatjuk, hogy a kijelölt időszakban mely metódusok futása tartott a legtovább. Ez a nézet kiválóan alkalmas arra, hogy beazonosítsuk azokat a metódusokat amelyeken érdemes lesz optimalizálni. Ha további infóra lenne szükségünk, lefúrhatunk azokhoz a PurePath-okhoz is ahol a kiválasztott metódus meghívásra került. 


Methods

A metódus nézetnél többek között kideríthetjük, hogy melyik metódus hívódott meg a legtöbbször, mennyi volt a metódusok átlagos végrehajtási ideje vagy hogy összesen mennyi időt vett igénybe a végrehajtásuk.


WebServices, Messaging

A Web szolgáltatásokról és a Messaging-ről is begyűjthetünk néhány információt az ezekhez tartozó dashboard-oknál vagy a lefúrások során.



Logging, Exceptions

Az előbbiekhez hasonlóan a PurePath-okból kiindulva vagy az időablakra való szűkítéssel megnézhetjük a napló üzeneteket és a keletkezett kivételeket is. Feliratkozhatunk egy-egy számunkra érdekes kivételre, majd lefúrhatunk azokhoz a PurePath-okhoz ahol ez előfordult. Érdemes megemlíteni, hogy az alkalmazás belső működéséhez tartozó kivételek is kijelzésre kerülnek, de ezeket mint Business Exception-öket el tudjuk rejteni.


Transaction Flow

A Transaction Flow nézetből megtudhatjuk, hogy a PurePath-ok honnan indultak ki, milyen alrendszereken haladtak keresztül és hogy hol mennyi időt töltöttek el, azaz beazonosíthatjuk azokat a rendszereket amik a belassulásokért felelősek.


Nagyvállalati környezetben legtöbbször nincs a teljes rendszerre kiterjedő architekturális leírás, hiányosan vagy egyáltalán nincsenek ledokumentálva az alkalmazások közötti kapcsolatok és függőségek. Valószínűleg költséges lenne, de gondoljunk bele ha az összes rendszerre feltelepítenénk a dynaTrace ágenseit, a Transaction Flow segítségével automatikusan feltérképezhetnénk a rendszer teljes architektúráját. Sőt! Mivel a feltérképezés folyamatos, mindig naprakészek információink is lennének.

Annak ellenére hogy csak a fontosabb lehetőségekre tértem ki, így a cikk végére azt hiszem már körvonalazódik hogy mire is képes a dynaTrace. A folytatásban a dynaTrace-es performancia monitorozásról fogok blogolni.

2012. június 1., péntek

DynaTrace - Kalandozás a szenzorok világában!

Frissítve: 2012.12.02.

A PurePath technológia lehetővé teszi, hogy az összes felhasználói műveletet teljes részletességgel lekövessük a hívási lánc alapján. Felvetődik a kérdés, hogy ez vajon nem fogja nagyon belassítani az alkalmazás futását? A válasz nem, az overhead az előző cikkben említett 2% körül marad mindaddig amíg a dynaTrace-t megfelelően használjuk és konfiguráljuk! A továbbiakban elmagyarázom a szenzorok működését, amiből kiderül hogy hogyan is tartható ez a minimális overhead.

DynaTrace szenzorok

A dynaTrace szenzorok feladata, hogy kinyerjék a szükséges adatokat és kontextus információkat (naplók, kivételek, cpu idők, futási idők, stb..) a vizsgált metódusokból. Kereskedelmi termék lévén, a szenzorok részletes működéséről nem esett szó a dynaTrace-es oktatáson, de egy kis Java ill. performancia mérési tudással a két szenzor típus alkalmazása alapján kikövetkeztethető!

Auto szenzorok - Mintavételezés

Az auto szenzorok olyan előre definiált szenzorok, amelyek mindig be vannak kapcsolva és rámutatnak a problémás, nagy végrehajtási idejű metódusokra. A megvalósítást tekintve az auto szenzorok a mintavételezés alapján működnek, azaz a háttérben néhány DynaTrace-es démon szál folyamatosan fut, amik a beállított mintavételezi gyakoriság alapján (pl.: 25ms) megvizsgálják az éppen futó szálak stack-jét és begyűjtik az adatokat.


A fenti ábrán a t1-t9 időpillanatokban történik a mintavételezés és 4 metódus van végrehajtás alatt. A metódus1 és metódus2 végig, a metódus3 részlegesen, a metódus4 pedig egyáltalán nem kerül rögzítésre a vizsgált időintervallumban. Látszik, hogy a mintavételezés nem szolgáltat pontos mérési eredményeket, de kiválóan alkalmas arra, hogy rámutasson a hosszan futó metódusokra (HotSpots) mindemellett az overhead végig stabil marad a mintavételezési gyakoriság függvényében. 

Metódus szenzorok - Instrumentáció

Miután az auto szenzorok rámutattak a problémás funkciókra, ezekre metódus/osztály/csomag szinten custom szenzorokat tudunk elhelyezni hogy pontosabb információkat nyerjünk ki. A metódus szenzorok az instrumentáció alapján működnek, azaz aspektus orientált módon rátelepednek a kódra és rögzítik a szükséges információkat. Bár az instrumentáció segítségével megkaphatjuk a pontos futási időket és hívási számot is, ezek állítgatására jobban oda kell figyelni, mert az overhead itt már a megfigyelt kód futásával lesz arányos. 

Smart szenzorok - Szenzor csomagok

Az web-alkalmazásunk által használt technológiák alapján, többféle szenzor csomagból válogathatunk: EJB, Spring, Struts, WebService, Hibernate, JDBC, XML, JMS, stb... valamint lehetőségünk van az általuk begyűjtendő információk finomhangolására is.

A szenzorok konkrét megvalósítása ennél azért trükkösebb lehet, mivel a gyakorlat azt mutatja, hogy az esetek 90%-ban elegendő információt szolgáltatnak az auto szenzorok is. Remélem sikerült felkeltenem az érdeklődésedet az elméleti bevezetőkkel, a következő részben pedig a gyakorlati oldaláról is megismerheted a dynaTrace-t.
 

2012. május 8., kedd

DynaTrace - Performancia menedzsment felsőfokon!

A banki stabilizációs projekt keretében alkalmazott egyik nagyágyú a dynaTrace volt, aminek a megismeréséhez az első héten egy 3 napos dynaTrace core oktatáson vettünk részt, majd az előadó segítségével felkonfiguráltuk az éles környezethez a dynaTrace-t. Mivel kifejezetten hasznosnak bizonyult a performancia jellegű problémák beazonosításához, így a következő cikksorozatommal egy bevezetést fogok nyújtani a dynaTrace világába.

A nagyvállalati alkalmazásoknál gyakran előforduló jelenség, hogy a felhasználók a nagy válaszidőkre, instabil és bugos alkalmazásokra vagy éppen az időszakosan elérhetetlen rendszerekre panaszkodnak. Jobb esetben ilyenkor megtörténik a hiba bejelentése, majd a fejlesztőkhöz napokkal később eljut az általában hiányosan kitöltött hibariport akik elkezdik az alrendszerekhez tartozó napló állományokat bújni és időnként felkeresik az architekteket némi plusz információ reményében hogy megoldást találjanak a problémára.

Mi a gond ezzel a megközelítéssel?
  • A problémák egyértelmű beazonosításához nem áll minden információ a rendelkezésünkre vagy ha igen, akkor túl sokáig tart a kinyerésük.
  • Nagyvállalati rendszerek esetén a felhasználók kérései több rendszeren is keresztülhaladnak ezért a belassulások, stabilitási problémák és a hibák beazonosítása kifejezetten nehéz feladat. A felderítés során leginkább a napló állományokra támaszkodhatunk, amik az egyes rendszereknél elszórva (nem központosítva) helyezkednek el.
  • A naplóállományok egyenkénti átnézése sok időt vehet igénybe és legtöbbször pont a számunkra fontos kontextus információk hiányoznak belőle.
  • Mivel a problémákra nem tudunk egyből reagálni, romlik a felhasználói elégedettség és csökken az üzleti teljesítőképesség is.
 

    Mi lenne a megoldás? 

    Egy olyan nézet, ahol is a felhasználók által végrehajtott összes műveletet teljes részletességgel real-time letudnánk követni. Azaz, hogy a kérések mikor és milyen rendszereken haladtak keresztül, az egyes alrendszereken belül milyen sorrendben milyen metódusok hívódtak meg és ezeknél mennyi időt töltött a végrehajtás. Igen, többek között pont erre lesz jó a dynaTrace! A dynaTrace egyik legnagyobb előnye, hogy ezen információk begyűjtéséhez sehol sem kell a kódhoz hozzányúlni, csupán egy JAVA/JVM vagy .NET/CLR argumentumot kell felvenni! Érdemes még megemlíteni, hogy a 2%-nál kevesebb overhead-nek köszönhetően éles környezetben is használható!

    A dynaTrace architektúra

    A dynaTrace egy performancia menedzsment és monitoring (APM) eszköz, amely lehetővé teszi a teljesítménybeli ill. stabilitási problémák analizálását és monitorozását, többrétegű heterogén (Support Matrix) rendszereken keresztül. Az egyedi felhasználói tranzakciók analizálása (7*24) a PurePath technológia segítségével történik, ami nem aggregált hanem a pontos értékekkel dolgozik.

     

    A fenti ábrán egy piros vonal jelöli a PurePath-t, vagyis a felhasználó által indított tranzakciót (kérést) ami végighalad az alrendszereken keresztül. A dynaTrace a felhasználók minden egyes kéréséhez egy új PurePath-t fog elmenteni, amihez a hívási lánc, a pontos végrehajtási idők, kivételek, naplóbejegyzések, metódus argumentumok és visszatérési értékek is rögzítésre kerülnek.

    A mérendő információk finomhangolásához szenzorokat definiálhatunk a szervereken. Minden szerverre egy-egy ágenst kell feltelepíteni, pl. Java esetében JVM argumentumon keresztül. Az ágensek, az általuk összegyűjtött információkat a PurePath Collector-nak adják tovább. A PurePath kollektorok nem végeznek semmilyen feldolgozást, csupán az ágensek adatait fogadják és továbbítják a dynaTrace Server felé ahol is begyűjtött információk tényleges feldolgozása történik. A dynaTrace Analysis Server feladata a begyűjtött heap dumpok feldolgozása, a Perfromance Warehouse pedig a historikus adatokat tárolásáért felel. A rögzített adatok monitorozásához és analizálásához a dynaTrace Client-el csatlakoznunk kell a dynaTrace Server-hez.

    Lassan már 4 hónapja használom a dynaTrace-t és ezalatt az idő alatt sikerült kiismernem a lehetőségeit és korlátait is, így ha bármilyen kérdésed lenne a dynaTrace-el kapcsolatban,  ne tartsd magadban hanem dobj meg egy kommenttel!

    A dynaTrace-es kalandozás nemsokára folytatódik...

    2012. május 1., kedd

    SWAT - Banki Stabilizációs Projekt

    Január óta az egyik nagy hazai bank stabilizációs projektében dolgozom. A 4 fős SWAT csapatban - így neveztek el minket :) - a feladatunk, hogy az intrabank és a hozzá kapcsolódó rendszerek teljesítménybeli és stabilitási problémáit felderítsük, majd a fejlesztőkkel és az üzemeltetőkkel egyeztetve elvégezzük a javításukat. Mivel TOP1-es projektről van szó, kiemelt prioritást és jogosultságokat kaptunk minden területen!


    A projekt során a fejlesztői és üzemeltetői ismereteimet is tudtam bővíteni, többek között megismertem egy egyedi és összetett bank informatikai architektúrát (legalábbis egy részét), foglalkoztam monitorozással, teljesítmény hangolással kliens ill. szerver oldalon, bug-ok felderítésével és javításával, dump-ok analizálásával és még sorolhatnám. Az elmúlt hónapok visszajelzései nagyon pozitívak voltak, jópár performancia és stabilitásbeli problémát javítottunk ki, a munkánk sikersztori lett bankon belül is!

    Bár a szigorú titoktartási kötelezettségem miatt a felderített problémákról és azok megoldásairól nem írhatok, az elkövetkező blog bejegyzéseimben elő fognak kerülni a munkám során alkalmazott elméleti és gyakorlati ismeretek a fent említett témakörökből. Elöljáróban még annyit, hogy a hagyományos fegyverzeten kívül használatba vettünk egy-két nagyágyút is melyekről hamarosan a blogomon is olvashatsz.

    A továbbiakban ezt a bejegyzést egyfajta gyűjtő topic-nak fogom felhasználni, ahova folyamatosan belinkelem majd a stabilizációs projekt kapcsán alkalmazott gyakorlati fogásokat és eszközök leírását! Ígérem érdemes lesz gyakran visszalátogatni, tőletek pedig annyit kérnék ha tetszett valamelyik bejegyzés írjatok egy kommentet mivel számomra ez a legfontosabb visszajelzés!

    DynaTrace

    2012. április 18., szerda

    Quartz - Bevetés Java EE környezetben

    Egy klaszterezett WebSphere 6.1 alkalmazás szerver alatt futó webalkalmazáshoz fogok egy olyan modult elkészíteni, amely minden nap 21:00 órakor végrehajtja a feliratkozott felhasználóknak a hírlevél elküldését. Az ismertetésre kerülő példa más alkalmazás szerveren vagy egy Apache Tomcat-en is - kisebb módosításokkal - bevethető!


    1. Döntések az ütemezés végrehajtásához

    Először is el kell döntenünk, hogy az időzítési adatok tárolását perzisztens vagy nem perzisztens módon kívánjuk végrehajtani. Bár a RamJobStore felkonfigurálása egyszerűbb, a biztonságosabb kezelés érdekében (pl.: szerver leállás miatti lekésett triggerek újratüzelése) érdemes a JdbcJobStore-t választani. A következő lépés, hogy eldöntsük melyik tranzakció típust használjuk a Quartz táblákat tartalmazó adatbázis eléréséhez. A JobStoreTX-re esett a választás, mivel az elkészített alkalmazás nem használja a WebSphere által kezelt JTA tranzakciókezelést. A WebSphere admin konzolon korábban felvett adatforrásra a jdbc/wasdb JNDI névvel fogok hivatkozni a quartz konfigban, nem pedig properties bejegyzésekkel.

    Mivel az alkalmazás egy klaszter több szerverére is telepítve lett, az ütemezés megfelelő végrehajtásához dönteni kell a Quartz klaszterezési lehetőségének kihasználása ill. az ütemezett feladatoknak a WebSphere klaszter egyik szerverén történő végrehajtása mellett. (Az utóbbit pl. az egyik szerver hoszt nevére való szűréssel tehetnénk meg.) A választásom a Quartz beépített klaszterezésére esett, mivel ez hibatűrő (az egyik szerver leállásakor a másik átveszi az időzített feladatok végrehajtását) és biztosítja a megfelelő terheléselosztást is.

    2. A Quartz konfigurálása

    Az alkalmazás Oracle adatbázist használ, ezért a quartz telepítési csomagban található (docs/table/tables_oracle.sql) szkriptet kell lefuttatni a Quartz által használt táblák létrehozásához. Végül az előzetes döntések alapján elkészített quartz.properties állományt tegyük ki az alkalmazás classpath-ára.
    #Main Scheduler
    org.quartz.scheduler.instanceName=WebSphereClusteredScheduler
    org.quartz.scheduler.instanceId=AUTO
    
    #ThreadPool
    org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount=1
    
    #JobStore
    org.quartz.jobStore.useProperties=false
    org.quartz.jobStore.misfireThreshold=60000
    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
    org.quartz.jobStore.dataSource=wasDs
    org.quartz.dataSource.wasDs.jndiURL=jdbc/wasdb
    org.quartz.jobStore.acquireTriggersWithinLock=true
    org.quartz.jobStore.txIsolationLevelSerializable=true
    
    #Clustered config
    org.quartz.jobStore.isClustered=true 
    org.quartz.jobStore.clusterCheckinInterval=10000
    
    #Update check
    org.quartz.scheduler.skipUpdateCheck=true

    3. A hírlevélküldési feladat időzítése

    A konténerben futó webalkalmazások esetén, a Quartz időzítő automatikus indításához és leállításához a web.xml fájlban kell felvenni egy listenert vagy egy startup servletet. A hírlevél küldéshez tartozó job és trigger inicializálását érdemes az alkalmazás indulásakor elvégezni, így ehhez célszerű létrehozni egy saját szervletet, SchedulerInitializer névvel. Bár a szervlet init() metódusa a klaszter minden szerverén lefut, az inicializálást csak az egyik szerveren kell végrehajtani, így elkerülhető az ütemezési feladatok többszöröződése.
     
      QuartzInitializer 
      
       org.quartz.ee.servlet.QuartzInitializerServlet
      
      
       start-scheduler-on-loadtrue
      
        shutdown-on-unloadtrue
      2
    
    
     
      
         SchedulerInitializer
        
       
         test.SchedulerInitializerServlet
        
       3
    
    Az init() metódusban történik a hírlevél küldési job és trigger szükség szerinti létrehozása, majd ellenőrzésképpen az infók kiíratása. Az alábbi Clean Coding elvek figyelembe vételével megalkotott kódrészlet a Quartz 2.1 -re épül, így az ennek megfelelő API-t használtam.
    public class SchedulerInitializerServlet extends HttpServlet{
     private Scheduler sched = null;
     private static final String GROUP_NAME="NG";
     private static final String NEWSLETTER_JOB_NAME="NLJ";
     private static final String NEWSLETTER_TRIGGER_NAME="NLT";
     private static final String CRON="0 0 21 * * ?";
     
     @Override
     public void init(ServletConfig cfg) throws ServletException{
       super.init(cfg); 
       startScheduling();
       listOfJobsAndTriggers();
     }
    
     private void startScheduling() throws Exception{
       initScheduler(); 
       if(!isSavedNewsletterJob()) 
         sched.scheduleJob(createNewsletterJobDetail(), 
         createNewsletterTrigger(CRON)); 
     }
    
     private void initScheduler() throws SchedulerException {
       if (sched == null)
         sched = StdSchedulerFactory.getDefaultScheduler(); 
       if (!sched.isStarted())
         sched.start();
     }
    
     private boolean isSavedNewsletterJob(){
       return sched.checkExists(
         JobKey.jobKey(NEWSLETTER_JOB_NAME,GROUP_NAME));
     }
    
     private JobDetail createNewsletterJobDetail() {
       return JobBuilder.newJob(NewsletterSenderJob.class)
         .withIdentity(NEWSLETTER_JOB_NAME, GROUP_NAME)
         .build();
     }
     
     private Trigger createNewsletterTrigger(String cron) { 
       return TriggerBuilder.newTrigger()
         .withIdentity(NEWSLETTER_TRIGGER_NAME, GROUP_NAME)
         .withSchedule(CronScheduleBuilder.cronSchedule(cron))
         .startNow()
         .build();
     }
    
     private void listOfJobsAndTriggers() throws Exception{
       for(String grp: sched.getJobGroupNames())
         for(JobKey jk : sched.getJobKeys(jobGroupEquals(grp)))
           log.info("Found job identified by:"+jk);
     
       for(String grp: sched.getTriggerGroupNames()) {
         for(TriggerKey tk : sched.getTriggerKeys(
          triggerGroupEquals(grp))) {
             log.info("Found trigger identified by:"+tk); 
     }
     
    }
    A hírlevél kiküldéséhez definiált CronTrigger tüzelésekor, a Job interface-t implementáló NewsletterSenderJob osztályból mindig egy új példány fog létrejönni, melynek az execute() metódusa lesz végrehajtva. A @DisallowConcurrentExecution annotáció biztosítja, hogy - JobDetails-enként - egyszerre csak egy példány fusson a NewsletterSender job-ból. Habár a @PersistJobDataAfterExecution működését jelenleg nem használom ki, az annotáció hozzáadásával elérhetővé válik, hogy a JobDetails-hez rendelt data objectek módosításai automatikusan mentésre kerüljenek.
    @DisallowConcurrentExecution
    @PersistJobDataAfterExecution
    public class NewsletterSenderJob implements Job{ 
     public NewsletterSenderJob() {}
     public void execute(JobExecutionContext context) 
       throws JobExecutionException {
         //newsletter sender logic
     }
    }

    2012. április 2., hétfő

    Quartz - A feladatütemező konfigurálása

    Az előző cikkben a Quartz által használt fogalmakról írtam, a mostani bejegyzésemben pedig a Quartz eltérő környezetekhez való felkonfigurálásáról fogok blogolni.

    A Quartz konfigurációs beállításait a classpath-ra elhelyezett quartz.properties fájlban adhatjuk meg, ami alapján a StdSchedulerFactory legyártja az időzítéshez használt Scheduler példányt. A RAMJobStore használatához elég a quartz.properties fájlt megírni, a JDBCJobStore használatához ezen felül még létre kell hozni a szükséges adatbázis táblákat is (/docs/dbTable mappa). A következőkben a quartz.properties fájl minimális konfigurációját fogom ismertetni néhány lehetséges környezethez.

    RAMJobStore – Standalone környezethez

    Az időzítési információkat az alkalmazás minden indulásakor inicializálni kell, továbbá a lekésett triggerekhez tartozó jobok újbóli végrehajtására nincs lehetőség.
    #Configure MainScheduler
    org.quartz.scheduler.instanceName = MyScheduler
    org.quartz.scheduler.instanceId = AUTO
    org.quartz.threadPool.threadCount = 3
    
    #Configure JobStore
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
    

    JDBCJobStore/JobStoreTX – Standalone környezethez

    A konfiguráció egy standalone java alkalmazás által használt beállításokat tartalmazza. Az ütemező adatainak perzisztens tárolásához egy MySQL adatbázis került bekonfigurálásra, melynek az attribútumait a datasource résznél property-kkel definiáltam.
    #Configure Main 
    Schedulerorg.quartz.scheduler.instanceName = MyTestScheduler
    org.quartz.scheduler.instanceId = AUTO
    org.quartz.threadPool.threadCount = 3
    
    #Configure JobStore
    org.quartz.jobStore.useProperties = true
    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    org.quartz.jobStore.dataSource=myTestDS
    
    #Configure Datasources (by properties)
    org.quartz.dataSource.myTestDS.driver=com.mysql.jdbc.Driver
    org.quartz.dataSource.myTestDS.URL=jdbc:mysql://localhost:3306/testQuartz
    org.quartz.dataSource.myTestDS.user=testQuartz
    org.quartz.dataSource.myTestDS.password=testQuartz
    org.quartz.dataSource.myTestDS.maxConnections=30
    

    JDBCJobStore/JobStoreCMT – Standalone környezethez

    A konfiguráció egy Java EE alkalmazás ütemezőjének beállításait mutatja. Az ütemező adatainak a tárolásához szintén egy MySQL adatbázis lett bekonfigurálva. A működéshez két datasource-t kell beállítani, egy JTA tranzakciókban résztvevő (myTestDS) és egy nem tranzakcionális (myTestDSNonManagedTX) datasource-t. Az adatforrásokat az előző példával ellentétben most nem property-vel, hanem JNDI-al adtam meg.
    #Configure Main Scheduler
    org.quartz.scheduler.instanceName = MyTestScheduler
    org.quartz.scheduler.instanceId = AUTO
    org.quartz.threadPool.threadCount = 3
    
    #Configure JobStore
    org.quartz.jobStore.useProperties = true
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT
    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    org.quartz.jobStore.dataSource = myTestDS
    org.quartz.jobStore.nonManagedTXDataSource = myTestDSNonManagedTX 
    
    #Configure Datasources (by jndi)
    org.quartz.dataSource.myTestDS.jndiURL=java:/dbDatasource
    org.quartz.dataSource.myTestDSNonManagedTX.jndiURL=java:/dbDatasourceNonManaged
    

    JDBCJobStore/JobStoreTX – Clustered környezethez

    Klaszterezett környezetben minden node-nak ugyanazt a quartz.properties beállításokat kell használnia, csupán a ThreadPool méret és az InstanceId lehet eltérő. A node-oknak egyedi instanceId-vel kell rendelkezniük, ami az AUTO értékkel könnyen megvalósítható.
    #Configure Main Scheduler
    org.quartz.scheduler.instanceName = MyClusteredTestScheduler
    org.quartz.scheduler.instanceId = AUTO
    org.quartz.threadPool.threadCount = 3
    
    #Configure JobStore
    org.quartz.jobStore.useProperties = true
    org.quartz.jobStore.acquireTriggersWithinLock=true
    org.quartz.jobStore.txIsolationLevelSerializable=true
    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    org.quartz.jobStore.dataSource = myTestDS
    
    #Clustered Configuration
    org.quartz.jobStore.isClustered = true 
    org.quartz.jobStore.clusterCheckinInterval = 10000
    
    #Configure Datasources (by properties)
    org.quartz.dataSource.myTestDS.driver=com.mysql.jdbc.Driver
    org.quartz.dataSource.myTestDS.URL=jdbc:mysql://localhost:3306/testQuartz
    org.quartz.dataSource.myTestDS.user=testQuartz
    org.quartz.dataSource.myTestDS.password=testQuartz
    org.quartz.dataSource.myTestDS.maxConnections=30
    
    A befejező részben egy WebSphere alatt futó webalkalmazáshoz fogok időzített feladatokat kódolni, ne hagyd ki a következő bejegyzésemet sem!

    2012. március 20., kedd

    Quartz - Feladatütemezés a Javából

    A web-alkalmazások fejlesztése során előbb vagy utóbb megjelennek olyan feladatok amelyeket folyamatosan végre kellene hajtani meghatározott időközönként. Ilyen feladat lehet például a hírlevelek heti egyszeri kiküldése, a keresési indexek óránkénti frissítése vagy éppen az inaktív felhasználók havi törlése. Továbbá vannak olyan taszkok is, melyeket egyetlen egyszer kell elvégezni egy adott jövőbeli időpontban.

    A Quartz egy tranzakciókezelést és klaszterezést is támogató nyílt forráskódú feladat ütemező, melyet egyaránt használhatunk Java SE ill. Java EE környezetben is, akár több ezer feladat ütemezett indításához. Mivel a hivatalos oldalon egy jól használható dokumentáció és sok minta példa segíti a Quartz megismerését, ezért a mostani leírásomat inkább egy áttekintő bejegyzésnek szántam. Először következzenek a Quartz 2 által használt fogalmak.

    Job
    Az a feladat, amit időzítve (N-szer) vagy ütemezetten (folyamatosan) végre kívánunk hajtani. A feladat mindig egy metódus meghívása lesz, mégpedig egy olyan osztálynak az execute() metódusa, ami implementálja a Job interface-t.

    JobDetail
    Egy job osztályból készített definíciós példány, ami a job-ot további tulajdonságokkal egészíti ki. Ilyen tulajdonság lehet a job neve, a job csoportja vagy éppen a data objectek (JobDataMap). Egy job-ból akár több JobDetails is létrehozható eltérő névvel, csoporttal és hozzárendelt adatokkal.

    JobDataMap
    A JobDataMap használatával data object-eket menthetünk el bármely JobDetail-hez, melyek a Job végrehajtása során elérhetők és módosíthatók az execute() metódus JobExecutionContext paraméterének felhasználásával. A JobDataMap-be mindig szerializálható objektumokat tegyünk, és ügyeljünk az eltérő osztály verzióikból származó problémákra is. Ajánlott a standard Java osztályokat használni (pl.:String, Long).

    Trigger
    Egy olyan esemény, ami kiváltja (tüzelés) a job végrehajtását. A kiváltó esemény lehet N-szer (SimpleTrigger) vagy folyamatosan ismétlődő (CronTrigger).

    Scheduler
    A jobok és a triggerek kezelését végzi, feladata pedig a jobok végrehajtása a triggerek tüzelésekor. A feladatok ütemezéséhez először is el kell indítani egy scheduler példányt, amit Java SE környezetben a kódból, programozott módon végezhetünk el, míg Java EE platformon általában az alkalmazásszerver indulásakor valósul meg. Az ütemező kikapcsolt/szünetelt állapotában, illetve az az alkalmazás szerver leállásakor a feladatok időzített végrehajtása is szünetel.

    JobStore
    A JobStore feladata a scheduler, a jobok és a triggerek működéséhez szükséges információk tárolása, melyet perzisztencia szerint az alábbi típusokba sorolhatunk:

    1. TerracottaJobStore
    • Kereskedelmi termék.
    • Az adatok perzisztenciáját a Terracotta szerver biztosítja.
    • Klaszterezett és Nem klaszterezett módban is használható.

    2. RamJobStore
    • Az időzítési információk memóriában történő tárolására szolgál.
    • Mivel nem perzisztens, az alkalmazás leállításával az időzítési információk elvesznek. 
     
    3. JDBCJobStore
    • Az ütemezési információk tárolása perzisztens módon az erre kijelölt adatbázisban történik.
    • A szerver leállás miatt lekésett triggerek újratüzelése megoldható a következő induláskor.
    • A Quartz adatabázist létrehozó és inicializáló SQL szkriptek, a quartz tömörített állomány docs/dbTables/ könyvtára alatt találhatók.

    3.1. A JDBCJobStore tranzakció típusai
    • JobStoreTX: A tranzakciókat a Quartz maga kezeli le, így standalone vagy JTA tranzakciót nem használó alkalmazásoknál érdemes használni.
    • JobStoreCMT: A menedzselt JTA tranzakcióra támaszkodik, így Enterprise környezetben ezt célszerű használni. Használatához, egy menedzselt és egy nem menedzselt datasource beállítása szükséges. A menedzselt datasource lehet lokális vagy XA típusú.

    3.2. A JDBCJobStore klaszterezési lehetősége
    • Minden node ugyanazt a Quartz adatbázist használja.
    • A Quartz biztosítja az automatikus load balancing-ot. Bármely trigger tüzelésekor mindig csak az egyik node fogja végrehajtani a jobot.
    • Fail-over biztosítása. Ha az egyik node kiesik a többi node ezt detektálja, így a félbeszakadt jobok ismételten végrehajtásra kerülnek.


    A folytatásban a Quartz különböző környezetekhez való bekonfigurálását fogom ismertetni.

    2012. március 1., csütörtök

    Szoftvertesztelő Verseny - Tesztelni Jó!

    A Masterfield oktatóközpont jóvoltából megrendezésre került az első magyarországi szoftvertesztelő verseny, amelyre korhatár nélkül bárki benevezhetett. A kezdeményezés a maga nemében egyedülálló, ugyanis szoftver teszteléses verseny Magyarországon eddig még nem volt!

    Mivel mindig is szerettem versenyezni (korábban pl. részt vettem az IBM48 programozó bajnokságon valamint a legjobb Java fejlesztő versenyen is) úgy gondoltam, itt a remek alkalom hogy szoftvertesztelésből is kipróbáljam magam! Habár tesztelőként hivatalosan még nem dolgoztam, a fejlesztés mellett sokszor mégis lehetőségem nyílt a funkcionális, terheléses vagy éppen a felületi tesztelésre, így ezt a versenyt nem hagyhattam ki! :)

    A tesztelő verseny egy online előselejtezővel indult, ahol is 10 alkalommal heti rendszerességgel kaptunk egy-egy teszteléshez kapcsolódó feladatot. Ami talán a legjobban tetszett, hogy a feladatok sokrétűek voltak, többek között: specifikáció felülvizsgálat, statikus kód ellenőrzés, hibajelentés készítése, dinamikus tesztelés, felületi teszt automatizálás, terheléses tesztelés, biztonsági tesztelés.


    A versenyre közel 300-an regisztráltak, ebből 100-an kezdtek neki a versenynek és kb. 50 versenyző volt aki komolyan végig is csinálta a feladatokat. Az elődöntő után a legjobb 20 versenyző jutott be az élő döntőbe! A döntő a MasterField oktatóközpontban került lebonyolításra, ahol is 4 egymásra épülő feladatot kellett megoldani 3 óra mínusz az elődöntőn elért helyezés * 1 perc  alatt! 

    A díjkiosztó a Danubius Health Spa Resort Helia hotelben került megrendezésre és a véleményem szerint kifejezetten jóra sikerült. Ezúton is köszi a szervezőknek! Remek volt a hangulat, megismerkedtem néhány hivatásos szoftvertesztelővel és személyesen is találkozhattam a tesztelés a gyakorlatban magazin szerkesztőivel.

    Az online fordulós eredményem alapján bekerültem a legjobb 20 szoftvertesztelő közé, a döntőn pedig a 15. helyen végeztem. Az eredménynek nagyon örültem, hasznos volt összemérni a tesztelési jártasságomat néhány hivatásos szoftvertesztelővel! 



    2012. február 22., szerda

    JMeter - Terheléses tesztelés a gyakorlatban

    Az előző bejegyzésemben véglegesítettem a JMeter-es teszt szkriptet, ebben a részben pedig kitérek a metrikákra majd összefoglalom a terheléses teszteléssel kapcsolatos tapasztalataimat. Kezdjük a mérendő jellemzők értelmezésével, melyeket az előző részben ismertetett Aggregate Report ill. a Summary Report segítségével kaphatunk meg.

    Áteresztő képesség (Throughput)
    Az áteresztőképesség megmutatja, hogy adott időegység alatt hány kérésre képes válaszolni a szerver. Az áteresztőképesség segítségével a szerver terhelhetőségét vizsgálhatjuk és akkor tekinthetjük megfelelőnek, ha hosszabb idő után (órák, napok) is konstans marad az értéke. 

    Átlagos válaszidő (Average, Mean)
    Az átlagos válaszidő, ami a kérés elküldésétől a válasz megérkezéséig eltelt idők átlagát adja. Az átlagos válaszidő időnként félrevezető is lehet, így az átlagot mindig a szórás és a min/max válaszidők tekintetében elemezzük. 

    Szórás (Standard Deviation)
    Az átlagtól való szórás mértéke megadja, hogy az értékek milyen messze estek az átlagtól, így ezzel a metrikával következtethetünk az átlag pontosságára. A kisebb szórás pontosabb átlagot mutat. Általános szabályként elmondható, hogy a szórás akkor tekinthető relevánsnak, ha az átlag felénél nem nagyobb az értéke.

    Felező érték (Median, 50% Line)
    A minták fele ez alá az érték alá esik. Az értéke akkor tekinthető mérvadónak, ha az adatok normál vagy egyenletes eloszlásúak. 

    90% Line 
    A minták 90%-a ez alá az érték alá esik. A mediánhoz hasonlóan az értéke akkor tekinthető mérvadónak, ha az adatok egyenletes vagy normál eloszlásúak.

    Min, Max 
    A minimális és a maximális válaszidőnek az értékét mutatja.


      Terheléses tesztelés a gyakorlatban

      A tesztek futtatása előtt először is fogalmazzuk meg, hogy mire vagyunk kíváncsiak! A példa kedvéért most vizsgáljuk meg, hogy hány felhasználóig terhelhető a rendszer ha minden oldal esetében 3.5 másodperc átlagos válaszidő alatt kívánunk maradni.

      A kérdés megválaszolásához a Summary Report eredményeit használhatjuk fel. Az első fázisban 1 órás időtartamokban futtassuk le a tesztet, úgy hogy a felhasználószámot óránként folyamatosan növeljük, majd egy excel táblázatba gyűjtsük ki az adott felhasználószámhoz tartozó eredményeket, amiből később grafikont is készíthetünk! Amikor valamelyik 1 órás teszt végén az oldalakhoz tartozó átlagos válaszidő meghaladja a 3.5 másodpercet, abbahagyhatjuk a tesztelést. Ha az eredménnyel nem vagyunk megelégedve a második fázisban jöhet a tunning, ahol is kiválasztjuk azt a felhasználószámot ahol a rendszer még éppen teljesítette a 3.5 sec kritériumot, majd egyszerre mindig csak egy tunning paramétert állítva - legyen ez JVM beállítás, Pool beállítás stb. - nézzük meg milyen irányban változik az eredmény, ha javulás látható tartsuk meg a beállított értéket és így haladjunk tovább.

      Tanácsok a JMeter 2.5 tesztek készítéséhez és futtatásához

      Bár a JMeter egy nagyon hasznos eszköz, pár apróságra azért érdemes odafigyelni!
      • Ha a Thread Pool beállításoknál megadjuk a "Loop Count" értékét, akkor a teszt vége fele a szálak fogyásakor néha lefagy a JMeter, érdemes inkább "Forever"-re állítani és mondjuk 1-2 óra után leállítani a tesztet.
      • Ha 20-30 percnél tovább kívánjuk futtatni a tesztjeinket akkor a Summary Report Listeneren kívül mást ne használjunk, mert néhány Listener esetén hamar elfogy a memória. A legjobb ha hosszú futtatás esetén konzolról indítjuk a tesztet az alábbi paranccsal: jmeter -n -t test.jmx -l test.jtl
      • A JMeter-es tesztek futtatása alatt monitorozzuk a szervert is (CPU, RAM, HDD), így beazonosíthatjuk a szűk erőforrásokat. Használhatjuk a JConsole-t vagy a VisualVM-et.
      • A HTTP Proxy Server "Patterns to exclude" beállításánál mindig szűrjük a cache-elt elemeket, mivel nem az "első látogatók"-hoz tartozó idők mérése a célunk.
      • Figyeljük meg, hogy a felhasználók átlagosan mennyi időt töltenek várakozással az éles rendszer oldalain és az időzítőket ezek alapján állítsuk be.
      • A teszteket ne arról a gépről indítsuk ahol a szerver is van, így a helyi futtatás nem fogja az eredményeket torzítani.
      • Ha van rá lehetőségünk a teszteket több órán át vagy napokig is futtassuk, így pontosabb eredményeket kapunk.
      • A tesztesetek bejelentkezéssel kezdődjenek és kijelentkezéssel záruljanak.
      • Az Aggregate Report ill Summary Report valamely mezőjébe belekattintva több tizedes jegy pontossággal is megtekinthetjük az értékeket.
      • Ha a rögzített http kérésekhez tartozó nevek nem beszédesek, a teszt felvétele közben egyből módosítsuk is ezeket.
      • A JMeter tesztek futtatása előtt az adatbázis tábláit mindig töltsük fel néhány száz rekorddal vagy akár annyival is amennyivel majd 4-5 év múlva számolunk, mivel a hibák egy része és a belassulások is legtöbbször csak nagyszámú rekord esetén jelentkeznek!

      A cikksorozat a közeljövőben még folytatódni fog, ahol is JSF és JBoss Seam alapú alkalmazások JMeter-es tesztelésének részleteiről fogok blogolni! Addig is várom az észrevételeket és hozzászólásokat!

      2012. február 13., hétfő

      JMeter - A performancia tesztelés hasznos fogásai

      Az előző cikkem folytatásaként a múltkor ismertetett JMeter-es tesztesetet fogom véglegesíteni, továbbá bemutatok pár hasznos gyakorlati fogást is.
       
      Időzítők hozzáadása

      A Recording Controller alá felvett HTTP kéréseket a JMeter szálak (mint felhasználók) szünet nélkül hajtják végre, így érdemes időzítőket (Timers) is felvenni a felhasználók gondolkodási idejének reprezentálásához. Az időzítők mindig egy adott hatókörhöz tartoznak, több időzítő felhasználása esetén a késleltetések összeadódnak. Többféle időzítő közül is választhatunk, azonban én a Gaussian Random Timer-t szoktam használni, ahol is megadhatunk egy konstans késleltetést és egy ehhez képesti eltérést a Gauss görbe szerint.

      Itt felmerül az a kérdés, hogy milyen várakozási időket állítsunk be az időzítőkhöz? Mivel a célunk a felhasználók gondolkodási idejének pontos modellezése, a válasz egyszerű! Az éles rendszeren figyeljük meg, hogy a felhasználók mennyi időt töltenek az egyes oldalakon és ezen megfigyelések alapján állítsuk be az értékeket!


      CSV alapú adatforrás kialakítása

      Adatforrásokat akkor érdemes felhasználni, amikor pl. a szerver elérhetőségét nem akarjuk beégetni a tesztesetbe vagy ha bizonyos kéréseket mondjuk felhasználónként eltérő paraméterekkel akarunk futtatni. A felhasználók belépése pont egy ilyen esemény, ahol is a "valódi" felhasználókhoz hasonlóan mindig egy újabb felhasználónév/jelszó párossal kellene elvégezni a bejelentkeztetést. Ehhez a CSV Data Set Config konfigurációs elemet használhatjuk fel az alábbi ábra alapján.


      A filename mezőben adjuk meg a csv fájl elérhetőségét, ami esetünkben a felhasználónév jelszó párosokat fogja tartalmazni. Tehát az adatokat a csv fájl sorai fogják tartalmazni, amelyekre az ${USERNAME} ill. ${PASSWORD} kifejezésekkel hivatkozhatunk a http kéréseknél mint ahogy az alábbi ábra is mutatja. Így egyszerűen megoldódott az egyedi felhasználók beléptetése a teszteléshez.


      Végül megjegyezném, hogy a csv adatok felolvasása "körbeforgó" működés szerint zajlik, azaz ha elfogytak az adatok a felolvasás elölről kezdődik.

      Ellenőrzési feltételek megadása

      Az ellenőrzési feltételek (Assertions) lehetőséget adnak arra, hogy a HTTP kérésekre kapott válaszok helyességét leellenőrizzük. Ilyen feltétel lehet például a HTTP 200-as státuszkód ellenőrzése vagy valamilyen szövegrészlet tartalmazásának vizsgálata a válaszban (pl.: ne legyen a 'hiba' szó az oldalon). A Size Assertion segítségével könnyen ki tudjuk szűrni, ha mondjuk nagy terhelésre üres oldalt vagy rövid hibaüzeneteket kapnánk vissza. A hatókörök ilyenkor is szerepet játszanak, mert amíg egy Recording Controller alá felvett assertionok minden kérésre kiértékelődnek, addig a HTTP kérésekhez felvett assertion-ök más elemre nem lesznek érvényesek. Az alábbi ábra egy response assertion-t mutat a 404-es hibára vonatkozólag.


      Mérési eredmények rögzítése és megtekintése

      Az erdmények rögzítéséhez a Recording Controller alá vegyünk fel néhány Listenert. Az Aggregate Report-ból (jobb klikk a Recording Controlleren/Listeners/Aggregate Report) vagy a Summary Report-ból kiolvashatók a fontosabb jellemzők, ahogy az alábbi ábra is mutatja. A mérési eredmények az egyes oldalakra vonatkozólag külön-külön is megjelennek, így ha valamelyik oldalnál magas értékeket kapnánk ott kellene kicsit körülnézni optimalizálási célokból!

      Itt jegyezném meg, hogy a belassulás okának kiderítése nem mindig egyszerű feladat, főleg amikor a kérések több rendszeren is keresztül haladnak pl. nagyvállalati és banki alkalmazásoknál! Ilyenkor általában a napló állományokból szokás kinyerni az információkat, de van erre egy egyszerűbb megoldás is amiről hamarosan írni is fogok! Ha a téma felkeltette az érdeklődésed, nézz vissza később is a blogomra! .)


      A Graph Results listener panelon a Summary Report néhány értékét láthatjuk kirajzolva egy diagramon, ami kifejezetten előnyös ha az értékek változását folyamatosan is szeretnénk követni.


      A View Results Tree pedig lehetőséget ad a HTTP kérések és a kapott HTTP válaszok megtekintésére, ami  hasznos tud lenni a teszt közbeni hibakereséskor vagy ha éppen arra lennénk kíváncsiak, hogy a csv adatforrásból milyen értékek kerültek behelyettesítésre.


      A JMeter teszt indítása

      Utolsó simításként a hírek, a termékek és a dokumentumok megtekintéséhez felvettem egy-egy ciklust ahol is egy elem lekérésére kerül sor. A ciklusra 3-as lefutási számot állítottam be, majd a ciklusok alá hozzáadtam egy-egy adatforrást amiben a lekérendő elemek azonosítói találhatók meg. Ezeket az adatforrásokat mindenféleképpen a ciklusok alá kell felvenni, egyébként ha a Recording Controller alá tettem volna be, akkor a ciklusok lefutásakor nem olvasódnának fel újabb értékek. (scoping)


      Végül is betettem minden szükséges elemet így elérkezett a teszt szkript indítása, amit a run menüpont start menüelemére való kattintással hajthatunk végre. A teszteset indítása után a jobb fenti ikon zöldre vált és látható amint a felhasználók száma eléri a Thread Group-nál megadott maximumot.

      Bár a teszt szkript elkészült, a következő bejegyzésem még biztos tartogat neked egy-két hasznos információt!