V dnešním článku se již potřetí budeme zabývat popisem programových nástrojů, které je možné využít pro monitorování aplikací běžících ve virtuálním stroji Javy (JVM). Předminule jsme se převážně zabývali nástroji ovládanými z příkazového řádku a minule především aplikací JConsole, která je v současnosti standardní součástí instalace JVM (minimálně se to týká instalace OpenJDK6, OpenJDK7, Oracle JDK6 a samozřejmě též Oracle JDK7). Dnes se naproti tomu budeme zabývat popisem zcela nového nástroje nazvaného Thermostat, který je, na rozdíl od JConsole, nutné do operačního systému Fedora nainstalovat ve formě zvláštního balíčku.
Monitorovací nástroj Thermostat
V předchozích dvou částech seriálu pojednávajícího o nástrojích určených pro monitorování aplikací běžících ve virtuálním stroji Javy jsme si popsali především ty nástroje, které se ovládají z příkazového řádku a minule jsme se pak zabývali převážně popisem nástroje JConsole (plným jménem Java Monitoring and Management Console), jenž je standardní součástí instalace JDK (tedy vývojového prostředí Javy), včetně OpenJDK6 a taktéž OpenJDK7, což je důležité, protože právě OpenJDK7 je dnes pro Fedoru výchozí JDK/JRE. Připomeňme si, že monitorovací aplikace JConsole je vybavena plnohodnotným grafickým uživatelským rozhraním (využívá přitom knihovnu Swing s nativním Look and Fell), v němž lze sledovat jak lokálně běžící virtuální stroje Javy, tak i JVM, které jsou spuštěny na vzdálených počítačích.
Díky možnosti připojení JConsole na vzdálený počítač je možné provádět sledování či analýzu javovských programů i na serverech, na nichž většinou nelze předpokládat, že bude nainstalována podpora pro běh aplikací s GUI. Připomeňme si, že s využitím nástroje JConsole je možné sledovat využití paměti virtuálního stroje Javy (jedná se především o obsazení haldy – heapu), dále pak lze sledovat stav jednotlivých vláken aplikace, zjistit počet tříd načtených do paměti JVM (takzvaný permgen space) a konečně je možné číst a v případě potřeby také nastavovat vlastnosti aplikace dostupné přes standardní rozhraní nabízené technologií JMX (Java Management Extensions). Tyto vlastnosti jsou dostupné přes takzvané „MBeans“ a příkladem aplikace, kterou je možné přes „MBeans“ ovládat je například databáze MongoDB.
Obrázek 1: Jedním ze standardních monitorovacích nástrojů ovládaných z příkazového řádku je i utilita nazvaná jmap, která dokáže různým způsobem analyzovat obsah haldy (heapu) a následně zjištěné informace vypsat v čitelné podobě na standardní výstup. Zajímavé je, že nástroj Thermostat, který bude podrobně popsaný v navazujících kapitolách, dokáže s jmap interně komunikovat.
Thermostat aneb vylepšená JConsole
S nástrojem JConsole zmíněným v předchozí kapitole se dříve či později setká prakticky každý administrátor či vývojář pracující s programovacím jazykem Java, ovšem v některých případech se může ukázat, že funkce nabízené tímto nástrojem nemusí být ve všech případech dostatečné. Jedná se především o ty případy, kdy je nutné získat přehled o objektech uložených na haldě (heapu), například při analýze problémů s obsazením či využitím haldy. Musíme si totiž uvědomit, že platforma Javy sice programátorům nabízí automatické správce paměti, to však v žádném případě neznamená, že by se o správu paměti programátoři nemuseli vůbec starat. Někdy je tomu spíše naopak, protože vyrobit memory leak je i v Javě poměrně snadné (i když ne tak snadné jako v jazycích bez automatických správců paměti).
Obrázek 2: Ukázka monitorovací aplikace JConsole v průběhu zjišťování obsazení haldy sledovanou aplikací. Problém nastane ve chvíli, kdy budeme chtít zjistit, jaké objekty jsou na haldě uloženy a jaký objem paměti byl pro každý z těchto objektů využit. Zde již totiž narazíme na omezené možnosti JConsole.
Samozřejmě, že je možné při sledování obsazení paměti zkombinovat možnosti JConsole a již popsaných nástrojů jmap a jhat (ovládaných z příkazové řádky), popř. použít některý komerčně dostupný nástroj, který například může nabídnou i integraci do integrovaných vývojových prostředí Eclipse, NetBeans atd. Ovšem v současnosti je již alternativně možné pro tuto činnost využít i prakticky zcela nový open source nástroj nazvaný Thermostat. Popisu tohoto nástroje se budeme věnovat v následujících kapitolách. Přitom se budeme soustředit především na jeho instalaci a provoz v operačních systémech Fedora, mj. i z toho důvodu, že pro Fedoru již existují balíčky s Thermostatem.
Instalace Thermostatu do Fedory
Thermostat je, podobně jako dříve zmíněný a popsaný nástroj JConsole, aplikací naprogramovanou přímo v Javě, kterou je možné v závislosti na preferencích uživatele ovládat buď z textové konzole (zde lze využít historii příkazů, částečně i doplňování příkazů a jejich parametrů atd.) nebo je možné využít plnohodnotné grafické uživatelské rozhraní (to bude preferovat většina uživatelů). V GUI se využívají různé typy grafů, pro jejichž zobrazení je použita knihovna JFreeChart, při ovládání z textové konzole se využívá knihovna JLine2 implementující již zmíněnou historii příkazů a navíc se některé údaje přečtené z monitorovaného virtuálního stroje Javy ukládají do dnes poměrně populární NoSQL databáze MongoDB.
Po přečtení předchozího odstavce by se mohlo zdát, že nakonfigurování a zprovoznění Thermostatu nebude kvůli závislostem na mnoha dalších balíčcích a knihovnách nijak snadné, ovšem vzhledem k tomu, že balíček s nástrojem Thermostat je již součástí standardního repositáře Fedory (přesněji řečeno se jedná o Fedoru 17 a Fedoru 18), je ve skutečnosti instalace Thermostatu velmi snadná, protože postačuje pod právy roota (viz též příkazy su a b) zadat do konzole následující příkaz:
yum install thermostat
Po potvrzení tohoto příkazu klávesou [Enter] by se nejprve měly zjistit všechny balíčky, které je nutné nainstalovat společně s Thermostatem takovým způsobem, aby byly vyřešeny všechny potřebné závislosti a posléze dojde k zobrazení otázky, zda se skutečně mají všechny závislé balíčky nainstalovat (volba -y tuto otázku dokáže potlačit, viz též man yum). Na mém testovacím stroji s Fedorou 17 se jednalo celkem o dvacet osm závislých balíčků, toto číslo se však samozřejmě s velkou pravděpodobností bude na jiných počítačích (a především na jiných architekturách – například na počítači s mikroprocesorem ARM) odlišovat.
Při instalaci Thermostatu je nutné mít na paměti, že je tento nástroj v současné verzi určen především pro práci s OpenJDK 7 či Oracle JDK 7, takže při pokusu o jeho spuštění se starší OpenJDK 6/Oracle JDK6 mohou nastat potíže – v případě Fedory 17 a Fedory 18 je však již OpenJDK7 součástí základního repositáře a současně i standardně instalovanou JDK/JRE, takže toto upozornění platí spíše pro ty uživatele, kteří například do svých systémů ručně instalují Oracle JDK6. Postup instalace nástroje Thermostat do Fedory 17 je ukázán na následujících třech screenshotech:
Obrázek 3: Po zadání příkazu yum install thermostat (příkaz musí být spuštěn s právy roota, resp. uživatelem, který tato práva má) dojde nejprve ke zjištění seznamu všech dalších balíčků, na nichž je Thermostat přímo či nepřímo závislý.
Obrázek 4: Následně jsou všechny závislé balíčky přehledně vypsány do tabulky a nástroj yum se zeptá, zda se má pokračovat v instalaci. Můžeme zde také vidět, že se instalační program chystá stahovat celkem 25 MB dat, přičemž největším balíčkem je MongoDB.
Obrázek 5: Úspěšný konec instalace a návrat do shellu.
Thermostat agent a Thermostat klient
Práce s nástrojem Thermostat je v jednom ohledu poněkud složitější, než je tomu v případě minule popsané utility JConsole, a to zejména z toho důvodu, že se Thermostat ve skutečnosti skládá ze dvou samostatně pracujících částí. První částí je takzvaný Thermostat agent (či agenti), druhou částí je Thermostat klient. Thermostat agent musí být spuštěn na tom počítači, na němž je spuštěn i sledovaný/monitorovaný virtuální stroj Javy. Agent se ke sledovanému JVM připojuje přes další pomocné nástroje a na požádání posílá požadované zjištěné informace klientovi. Naproti tomu Thermostat klient běží na počítači uživatele (programátora, administrátora) a může buď používat textovou konzoli nebo plnohodnotné grafické uživatelské rozhraní (v tomto případě má k dispozici mnohem více možností, jak s klientem pracovat).
Obrázek 6: Pro spuštění Thermostat agenta i Thermostat klienta se používá stejný příkaz „thermostat“. Pokud se tento příkaz spustí bez parametrů, vypíše se na standardní výstup informace o tom, jaké parametry jsou pro danou verzi nástroje Thermostat podporovány. Nejdůležitější jsou parametry „service“, „gui“ a "shell", s nimiž se podrobněji seznámíme v dalším textu.
Spuštění agenta nástroje Thermostat
Pokud se sledovaný virtuální stroj Javy nachází přímo na počítači uživatele, je konfigurace jednodušší, protože na stejném počítači bude spuštěn jak Thermostat agent, tak i Thermostat klient. Zajímavé je, že jak Thermostat agent, tak i Thermostat klient (zde je myšlen terminálový klient i klient s grafickým uživatelským rozhraním) se startuje s využitím stejného příkazu, kterému se však musí pokaždé zadat rozdílné parametry. Podívejme se nejprve na to, jakým způsobem se spouští Thermostat agent (pokud totiž žádný agent nepoběží, nebude možné smysluplně použít ani Thermostat klienta). Spuštění agenta není ve skutečnosti nic složitého, protože z příkazové řádky postačuje zadat následující příkaz:
thermostat service --start
Tento příkaz ve skutečnosti interně provede dvě akce. Nejprve se spustí databáze MongoDB, do které agent postupně ukládá naměřená data a posléze se spustí vlastní agent. Na standardní výstup se přitom vypíše jednoznačný identifikátor agenta, který lze použít ve chvíli, kdy se Thermostat klient bude připojovat k většímu množství agentů.
Obrázek 7: Spuštění Thermostat agenta s využitím příkazu „thermostat service --start“. Z tohoto výpisu je patrné, že se nejdříve skutečně spustila databáze MongoDB a následně se spustil i agent, jemuž byl přiřazen jednoznačný identifikátor.
Spuštění GUI klienta nástroje Thermostat
Ve chvíli, kdy je spuštěna instance minimálně jednoho Thermostat agenta (samozřejmě společně s databází MongoDB, do níž bude agent zapisovat naměřená data), je již možné spustit i vlastního Thermostat klienta. V této kapitole i v kapitole navazující se budeme zabývat především klientem vybaveným plnohodnotným grafickým uživatelským rozhraním, který se ovládá mnohem jednodušeji než klient ovládaný z terminálu. Na druhou stranu je však práci klienta využívajícího pro vstup i výstup všech údajů textový terminál možné poměrně snadno zautomatizovat, například s využitím nástroje Expect (to by však bylo téma na celý článek).
Vraťme se však ke klientské části Thermostatu vybavené plnohodnotným grafickým uživatelským rozhraním. Tato aplikace pro svůj běh samozřejmě vyžaduje běžící X Window, lze ji však v případě potřeby provozovat i na vzdáleném počítači s využitím VNC či X Window protokolu tunelovaného přes ssh. Thermostat klient s grafickým uživatelským rozhraním se spustí následujícím příkazem:
thermostat gui
Obrázek 8: Spuštění Thermostat klienta s grafickým uživatelským rozhraním s využitím příkazu „thermostat gui“.
Po spuštění klientské části se ve starší verzi Thermostatu nejdříve objeví dialog nabízející spojení s lokálně běžícím agentem, se vzdáleným agentem popř. monitorování virtuálních strojů Javy běžících v clusteru. Nová verze již tento dialog nebude využívat, a to především z toho důvodu, že poslední možnost (Javovské virtuální stroje v clusteru) prozatím není implementována.
Obrázek 9: Ve starší verzi Thermostatu se při spuštění GUI klienta nejprve objeví tento dialog s výběrem možností sledování JVM.
Sledování aplikace běžící lokálně
Pro jednoduchost budeme předpokládat, že budeme sledovat lokální JVM, tj. budeme se připojovat k Thermostat agentovi, který běží na stejném stroji jako Thermostat klient. V klientovi je na levé straně zobrazena stromová struktura obsahující všechny agenty, k nimž je klient připojen a současně i všechny virtuální stroje Javy, které může daný agent sledovat (každý agent sleduje pouze JVM běžící na stejném počítači). V případě, že se připojíme pouze k lokálnímu agentovi, bude zde zobrazená stromová struktura ve skutečnosti velmi jednoduchá – strom totiž bude obsahovat pouze jeden uzel pojmenovaný podle síťového jména počítače a v tomto uzlu budou zobrazeny všechny běžící virtuální stroje Javy a tím pádem i všechny lokální javovské aplikace.
Obrázek 10: Úvodní okno Thermostat klienta v případě, že jsme se připojili pouze k lokálně běžícímu agentovi. Stromová struktura v levé části okna obsahuje pouze jeden uzel se síťovým jménem počítače a pod tímto uzlem jsou zobrazeny všechny běžící virtuální stroje Javy. Každý virtuální stroj je pojmenován podle třídy, z níž je javovská aplikace spuštěna (pro běžné aplikace se jedná o třídu se statickou metodou public void main). Na tomto obrázku je patrné, že na sledovaném stroji běží celkem osm javovských aplikací. Konkrétně se jedná o dva Thermostat agenty (i to jsou samozřejmě javovské aplikace), vlastního Thermostat klienta a navíc ještě o několik běžících testů.
Popis grafického uživatelského rozhraní nástroje Thermostat
Popišme si nyní základní prvky grafického uživatelského rozhraní klientské části Thermostatu. V levé části se nachází již zmíněná stromová struktura obsahující seznam všech agentů, k nimž se klient připojil a pro každého agenta se zobrazují všechny sledované virtuální stroje Javy. Nad tímto stromem se nachází textové políčko, které lze využít k rychlé filtraci agentů a sledovaných aplikací – stačí do tohoto políčka napsat část názvu agenta/aplikace a po stisku klávesy Enter či kliknutí na lupu se údaje ve stromu vyfiltrují.
Tuto funkci lze s výhodou použít ve chvíli, kdy Thermostat klient sleduje několik desítek JVM. Navíc je možné přes hlavní menu (položka Edit) zvolit, zda se ve stromu mají zobrazovat pouze běžící (živé) aplikace, nebo i aplikace, které již byly ukončeny. V pravé části okna se nachází šest listů (tabů), jejichž funkce se vzdáleně podobá listům „konkurenčního“ nástroje JConsole.
List „Overview“
Údaje zobrazené na prvním listu nazvaném „Overview“ (viz též screenshot číslo 10 a 11) pravděpodobně není zapotřebí nijak podrobně popisovat. V závislosti na tom, zda je ve stromě nalevo vybrán pouze uzel představující monitorovaný počítač či přímo konkrétní javovskou aplikaci, mohou být na tomto listu zobrazeny dva typy údajů.
Buď zde jsou zobrazeny informace o konfiguraci počítače (síťové jméno, instalované procesory a operační paměť, síťová rozhraní, právě spuštěný operační systém...), nebo zde nalezneme informace o čísle procesu (viz též příkaz jps), verzi virtuálního stroje Javy, jméno třídy, která je virtuálním strojem spuštěna jako třída hlavní a také jsou zde zobrazeny všechny případné argumenty, které jsou virtuálnímu stroji Javy předány při jeho spuštění. Zastavíme se pouze u údaje Stop time, který buď vypisuje řetězec „Running“ v případě, že daný proces/aplikace nebyl prozatím ukončen, nebo je zde zobrazen čas ukončení aplikace.
Obrázek 11: Obsah listu „Overview“ ve chvíli, kdy je ve stromu vybrána nějaká běžící či pozastavená javovská aplikace.
List „CPU“
Následuje popis listu nazvaného příhodně „CPU“. Tento list obsahuje pouze jeden graf s vytížením mikroprocesoru (či v dnešní době spíše procesorových jader) aplikací spuštěné ve virtuálním stroji Javy. Měřítko na vertikální ose se samozřejmě mění automaticky v závislosti na maximálním vytížení ve vybraném časovém okamžiku. Na ose horizontální lze měřítko jednoduše změnit zadáním číselné hodnoty do editačního pole umístěného pod grafem a následně výběrem vhodné časové jednotky. Je tak možné si relativně snadno přizpůsobit hloubku pohledu do historie práce JVM (a to klidně i v rozmezí stovek let :-). V nově připravované verzi Thermostatu bude ještě možné údaje na horizontální ose posouvat a zaměřit se tak na určité okamžiky, kdy například došlo k neočekávanému vytížení aplikačního serveru atd.
Obrázek 12: Obsah listu „CPU“. V dolní části se nachází editační pole a výběrový seznam. S využitím těchto ovládacích prvků je možné změnit měřítko použité na horizontální ose grafu.
List „GC“
Další list se jmenuje „GC“ a jak zajisté očekáváte, jsou zde zobrazeny informace o správcích paměti (GC – Garbage Collector). V závislosti na tom, jaký typ správců paměti je vybrán při spouštění virtuálního stroje Javy se na tomto listu mohou objevovat různé grafy, které obsahují časy běhu GC nad různými oblastmi v haldě. Tyto údaje lze například použít pro nastavování parametrů GC a samozřejmě pro sledování chování GC u aplikací běžících po dlouhou dobu, u nichž se požaduje co nejvyšší propustnost – typickou doménou jsou aplikační servery.
Podobně jako na listu „CPU“, i zde je možné pro každý graf vybrat vhodné časové měřítko horizontální osy, prozatím však nelze (alespoň v současné verzi Thermostatu) zkombinovat tyto grafy s dalšími grafy, které zobrazují například skutečné využití haldy.
List „Memory“
Z hlediska administrátora javovských aplikačních serverů patří mezi pravděpodobně nejdůležitější údaje informace o obsazení haldy (heapu) virtuálního stroje Javy. Tyto údaje jsou v souhrnné podobě zobrazeny na listu „Memory“. Halda je většinou rozdělena do několika oblastí, přičemž se objekty podle své „životnosti“ mohou mezi těmito oblastmi kopírovat, popř. se již „neživé“ objekty z haldy automaticky odstraňují správcem paměti. Velikosti těchto oblastí, přesně řečeno poměr mezi nimi, je samozřejmě možné měnit při startu virtuálního stroje Javy a grafy zobrazené na listu „Memory“ mohou programátorům i administrátorům v této poměrně heuristické práci pomoci. Podrobnosti si řekneme v navazující části tohoto seriálu.
Obrázek 14: Obsah listu „Memory“.
List „Memory Analyzer“
Pravděpodobně nejdůležitější skupinou informací, kterou lze s využitím nástroje Thermostat sledovat, je aktuální obsah haldy. Pro tento účel slouží list nazvaný příhodně „Memory Analyzer“, na němž je implicitně umístěn pouze graf zobrazující celkové využití haldy. Důležité je ovšem tlačítko „Heap dump“ sloužící k získání otisku obsahu haldy v libovolném časovém okamžiku. Pokud je toto tlačítko stisknuto, provede se analýza aktuálního obsahu haldy (s uložením výsledku do databáze MongoDB) a časový okamžik, kdy byla tato analýza provedena, je zobrazen v seznamu pod tímto tlačítkem. Posléze je možné v tabulce pod grafem vypsat počet instancí vybraných tříd (je zde možné provést vyhledávání i řazení) i celkovou velikost pro všechny instance vybrané třídy.
Obrázek 15: Obsah listu „Memory Analyzer“ ve chvíli, kdy ještě nedošlo k analýze obsahu haldy.
Obrázek 16: Pohled na tabulku s heap dumpem. Pokud se vám tabulka nezobrazí, znamená to ve většině případů pouze nutnost posunout vodorovný rozdělovník oddělující graf od spodní části listu.
List „Classes“
List „Classes“ je oproti předchozím dvěma listům velmi jednoduchý a přehledný, protože obsahuje pouze jediný graf, v němž je vynesen celkový počet tříd načtených do virtuálního stroje Javy. Tento graf je vhodné sledovat tehdy, pokud dojde k chybovým hlášením virtuálního stroje z toho důvodu, že již nebude možné načíst na haldu další třídu. Tato chyba může nastat ve chvíli, kdy nejsou správně nakonfigurovány poměry mezi jednotlivými oblastmi, z nichž se halda skládá. Podrobnosti si opět řekneme příště.