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.
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.
Ne maradj le a folytatásról sem!
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!