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!

    2012. február 1., szerda

    JMeter - Webalkalmazások terhelési tesztelése

    A Selenium-hoz hasonlóan már több projekt keretében is használtam a JMeter-t, így most elérkezett az idő hogy összefoglaljam a személyes tapasztalataimat egy gyakorlatias leírás keretében.

    A JMeter segítségével kliens-szerver alapú alkalmazások teljesítményét tudjuk megvizsgálni különböző terhelési szinteken. Megtekinthetjük, hogy hogyan reagálna a hétköznapi terhelésre a web-alkalmazásunk, de akár azt is megtudhatjuk hogy melyik komponens lenne a szűk keresztmetszet egy nemvárt nagyobb terhelés esetén. Bár a mostani bejegyzésemben a webalkalmazások terhelési tesztelésére fogok szorítkozni, a JMeter lehetőséget ad web-szolgáltatások, ftp szerver vagy éppen adatbázis szerver tesztelésére is. A webalkalmazások tesztelésénél a JMeter alapvetően HTTP kéréseket küld és fogad, de eltérően a böngészőktől nem futtatja le a JavaScripteket és nem is jeleníti meg az oldalt, így ezek az idők nem fognak szerepelni a mért adatokban.

    Érdemes megemlíteni, hogy az Apache JMeter-t nemcsak teljesítmény teszteléskor, hanem bármikor bevethetjük amikor hosszabb ideig tartó folyamatos terhelést szeretnénk generálni. Ilyen eset lehet például a performancia tuningolásához szükséges realisztikus terhelés generálása vagy egy hosszabb web-alkalmazás futtatás végrehajtása a memória szivárgások kimutatásához.

    A használathoz először is töltsük le a JMeter 2.5-ös verzióját, majd indítsuk el a java -Xms512m -Xmx512m -XX:MaxPermSize=512m -jar ApacheJMeter.jar paranccsal, legalább ekkora memória beállítások használatával. A JMeter elindulása után megjelennek a TestPlan és a WorkBench csomópontok a baloldali panelon. A TestPlan lesz a tesztesetünk gyökér csomópontja, ami alá egyből vegyünk is fel egy ThreadGroup (TestPlan jobb klikk/add/Threads/ThreadGroup) elemet.

    A ThreadGroup-nál definiált szálak (number of threads) egy-egy konkurens felhasználót fognak reprezentálni a tesztelés során, amelyek egymástól függetlenül hajtják majd végre az elkészített tesztesetet. Ugyanitt megadható a felfutási idő (Ramp-Up Period), azaz hogy hány másodperc teljen el amíg az összes szál (mint felhasználó) elkezdi a futását. Pl. ha a felhasználók száma 50, a felfutási idő 25 másodperc, akkor másodpercenként 2 új szál lesz elindítva. A lefutások számával (loop count) pedig megadhatjuk, hogy felhasználónként hányszor legyen a teszt végrehajtva vagy beállíthatjuk azt is, hogy folyamatosan fusson (forever).


    A szerverhez küldendő kéréseket mintákkal (Samplers) adhatjuk meg. A JMeter sokféle kérés típust támogat, többek között a JMS, JDBC, FTP, LDAP, AJP, TCP, SOAP kéréseket, azonban most csak HTTP ill. HTTPS kérésekkel fogok dolgozni. A vezérlők (Logic Controllers), lehetőséget adnak hogy a minták küldéséhez valamilyen logikát is rendeljünk. (pl.:feltétel, ciklus, véletlenszerű választás kérések között stb...).

    A HTTP kérések egyenkénti "kézzel" történő felvétele, majd az attribútumok beállítása sok időt vehet igénybe, így célszerű a JMeter HTTP Proxy Server lehetőségét kihasználni, ami lehetővé teszi hogy a böngészőben végrehajtott HTTP kéréseket automatikusan rögzítsük a JMeter-es tesztesetünkbe. Ehhez először is a ThreadGroup-hoz vegyünk fel egy Recording Controller-t, ami alá a HTTP Proxy Server majd automatikusan beteszi a rögzített HTTP mintákat.

    A Recording Controller-hez ezután adjuk hozzá a következő konfigurációs elemeket (Configuration Elements), melyek mindig az adott scope elején - azaz a minták előtt - kerülnek feldolgozásra: HTTP Request Defaults, HTTP Header Manager, HTTP Cookie Manager. A HTTP Request Defaults-al alapértelmezett értékeket (pl. host, port) adhatunk meg az aktuális scope-hoz tartozó HTTP kéréseket reprezentáló mintáknak, a HTTP Header Manager segítségével pedig felülírhatjuk a HTTP fejléc információit (pl. user-agent). A HTTP Cookie Manager hozzáadásával, a rögzített mintákhoz tartozó cookie információk elmentődnek és a kérésekkel továbbítódnak.

    Végül vegyük fel a HTTP Proxy Server-t (WorkBench/add/Non-Test Elements/ HTTP Proxy Server) a WorkBench csomópont alá, majd az alábbi ábra alapján töltsük ki a mezőket.


    A port mezőnél adjunk meg egy szabad portot amit majd a böngésző proxy beállításainál is állítsunk be a HTTP és a HTTPS protokollokhoz. Ezután válasszuk ki az általunk létrehozott Recording Controllert és adjuk meg, hogy az egyes oldalakhoz tartozó kéréseket külön Controller-be tegye. Válasszuk ki a HTTP Header mentését és a mintákhoz a HTTP4Client típust. Az "URL Patterns to Include" résznél reguláris kifejezéssel megadhatjuk, hogy milyen URL-ekre érkező kérések legyenek rögzítve, a mezőt üresen hagyva minden kérés mentésre kerül! Az "URL Patterns to exclude"-nál pedig azt definiálhatjuk, hogy milyen kérések ne kerüljenek felvételre. Fontos, hogy a képeket, css, js stb. zárjuk ki mivel ezek a második lekéréstől kezdve már a browser cache-ből jönnek (de ezt azért ellenőrizzük le egy HTTPFox segítségével) így a folyamatos lekérésük torzítaná a mérési eredményeket. Az alábbi ábrán a Firefox proxy beállítása látható.


    Ha ezzel megvagyunk nyomjunk rá a HTTP Proxy Server panel alján található Start gombra és a böngészőben menjünk végig azokon az oldalakon és akciókon amiket a tesztesetben felszeretnénk venni. A teszteset felvétele közben jól látható, hogy a HTTP kérések folyamatosan felvételre kerülnek a Recording Controller elemhez. A teszteset végén, a felvételt a Stop gombra való kattintással tudjuk leállítani. A minta kedvéért a tesztesetet egy portálon vettem fel ahol is a bejelenetkezés után megnéztem egy hírt és néhány infótár bejegyzést, majd kiléptem a felhasználóval, lásd a lenti ábrát.


    A teszteset szépen alakul, azonban az indítás előtt még pár dolgot be kell állítani, de ezekről majd a következő részben fogok írni.