V reakcích čtenářů minulý dílů toho seriálu se objevovaly dotazy typu, jak je Cocoon rychlý či výkonný, zdali všechny ty XML transformace (a zvláště transformace XSL) nezpůsobí nízký výkon celé aplikace. Tehdy jsem slíbil, že to příležitostně změřím a o výsledky se podělím s čtenáři. Protože vánoční a novoroční čas je k plnění slibů přímo stvořený, rozhodl jsem do tohoto dílu zařadit úvahy, co je a co není rychlé v Cocoonu a podělit se o výsledky měření výkonu webového fotoalba, které jsme vytvořili v minulých dílech. To znamená, že navzdory názvu seriálu zde nenajdete ucelený příklad, ale spíše úvahy a zkušenosti. A protože v polovině listopadu byla vydána novější verze Cocoonu (2.1.3), podíváme se, zda stojí za to si ji nainstalovat. A rovnou tím začneme.
Cocoon 2.1.3 – co je nového
Nejzajímavější je asi (alespoň pro mne) přepracování příkladu „Petstore“. Je to funkční „e-Zverimex“. Pokud znáte JSP, tak jeho funkcionalita by měla odpovídat témuž příkladu z tutoriálu JSP. Jak je v Cocoonu zvykem, vše se dá dělat několika (občas i mnoha :-) způsoby. Základ Petstoru je pro ukázku naimplementován čtyřikrát: jako XSP, JXPath, Jexl a šablona Velocity. Využívá flowscript a pro některé formuláře také Woody (nyní se tomu říká Cocoon Forms), což je asi nejzajímavější přístup k problematice formulářů na serverové straně, se kterým jsem se zatím setkal. Na Woody (Cocoon Forms) se určitě v tomto seriálu podíváme blíže.
Kromě toho jsou zde převážně opravy chyb, drobná vylepšení a aktualizace knihoven. Protože se několik vylepšení i oprav týká i výše zmíněného bloku Woody, doporučuji tuto aktualizaci Cocoonu nainstalovat. Postup byl popsán v minulých dílech a nijak se nezměnil.
Výkon Cocoonu a jeho ladění
V mysli mnoha z nás je zafixováno: XML = pomalý. To ale rozhodně vždy platit nemusí. Koncepce Cocoonu byla zvolena tak, aby režie, kterou XML jako obecný standard zcela jistě přináší, byla co nejmenší. Komponenty jsou poolovány (velikosti poolu lze doladit v souboru „cocoon.xconf“ nebo v mapě dané aplikace). Při správné velikosti poolu Cocoon nevytváří nové instance komponent (je to dost drahá operace), nýbrž si vyžádá komponentu z poolu a po použití ji tam zase vrátí. Implicitní pool není příliš velký a pokud vaše aplikace očekává např. 100 současných dotazů, rozhodně byste jej měli zvětšit.
Obsah roury může být kešován. Pokud klient žádá později stejný obsah, vrátí se (pokud možno) ten dříve vytvořený z keše. Protože kešování celé roury nelze vždy zajistit, Cocoon inteligentně kešuje „kam až to jde“ (například výsledek generátoru je po první transformaci kešován, další transformace už nemusí jít kešovat). Ale i kešování je poměrně drahá operace, takže je možné ji částečně ovlivnit nebo v krajním případě deklarovat rouru jako nekešujicí. Pro explicitní rozdělení, co kešovat a co ne, lze vhodně využít např. interní roury. Zajímavé také je, že efektivita kešování klesá, pokud je aplikace hlouběji v adresářové struktuře. Další pravidlo, zaměřené spíše na chování proxy a klientů, doporučuje v rouře co nejvíce používat parametr expires, což je možné zařídit v mapě například takto:
<map:pipeline>
<map:parameter name="expires" value="access plus 1 minutes"/>
...
</map:pipeline>
Většina čtenářů akceptovala, že pokud se v rouře předávají XML data jako události SAX, může to být celkem efektivní. Nejvíce nedůvěry ale budí použití transformace XSLT v rouře. Cocoon umí použít XSLTC (XSLT Compiler), který XSL dokument zkompiluje do javovských tříd (translets), což XSL transformaci znatelně zrychlí. Největší díl odpovědnosti leží ale v návrhu vlastních XML dat. Pokud XML data svou strukturou a logikou budou hodně odlišná od struktury a logiky požadované prezentace (např. HTML), budeme potřebovat složitý XSL dokument pro transformaci a ta pak bude pomalá. Z tohoto hlediska např. jinak opravdu pěkný a užitečný Docbook není příliš efektivní pro Cocoon. Platí dvě základní pravidla:
- V rouře musí být co nejméně XSL transformací. Ideální je jedna (nebo žádná). Máte-li tam více než dvě, zamyslete se, zda by to nešlo udělat jinak.
- XSL transformace musí být co nejjednodušší. Vyhněte se větvení, třídění a podobným operacím. Pro případné složitější operace si napište vlastní transformátor, který bude pracovat nad událostmi SAX.
XSLT umožňuje také definovat některé transformace různým způsobem. Některé způsoby jsou efektivní, jiné méně. Bude-li XSL transformace pomalá, můžete se podívat na stylesheet, zda jej nelze napsat lépe.
Režie XSL transformace, ale i roury samotné může však podstatně záviset i na rozsahu XML dat, která jsou zpracovávána. Cocoon není určen k tomu, aby přímo transformoval desetimegabajtový XML soubor nebo dokonce pomocí XSL transformace vybral z něj pár kilobajtů. Máte-li XML soubory větší než pár desítek kilobajtů, zvažte použití XML databáze, případně relační databáze, pokud tomu odpovídá charakter dat. Cocoon s oběma umí komunikovat.
Kdo ani teď nevěří výkonu XSL transformace, může zkusit transformaci STX (Streaming Transformations for XML), která je určena přímo pro proud událostí SAX. Měla by být tedy rychlejší než XSLT. Cocoon obsahuje implementaci STX, nicméně tato část ještě není považována za stabilní.
V Cocoonu jsou i další časově hodně náročné transformace, jako například generování PDF nebo transformace SVG na JPEG apod. Zvažte, zda je vždy generován skutečně dynamický obsah. Alespoň částečně statický obsah může být např. pravidelně generován nějakou dávkou. Cocoon umí otestovat, zda např. PDF soubor existuje, a podle toho se zachovat (zaslat jej nebo jej dynamicky vygenerovat).
Pokud ladíte výkon jednotlivých kroků roury, bude se vám nejspíše hodit Cocoon Profiler.
Dalším způsobem, jak zvýšit výkon Cocoonu, je možnost posílat statický obsah mimo Cocoon. Například je možné nainstalovat Tomcat s Apachem tak, že statický obsah zasílá klientovi Apache, dynamický cocoonová aplikace (běžící pod Tomcatem). Údajně jsou i výkonové rozdíly v jednotlivých servletových kontejnerech (ve prospěch komerčních), ale to jsem neměl možnost ověřit. Jiným způsobem, jak pomoci výkonu, je použití transparentní proxy s keší (SQUID). Obrázky a soubory s kaskádovými styly je zbytečné znovu a znovu zasílat např. Tomcatem (pokud je Cocoon dynamicky negeneruje), může být také zbytečné kešovat je v Cocoonu.
Poměrně levnou možností, jak zrychlit aplikaci v Cocoonu, je použít nejnovější JVM a zamyslet se nad parametry, jako jsou velikost hromady, počáteční paměť a další.
Fotoalbum – měření výkonu
Abychom si udělali obrázek o výkonu Cocoonu, pokusil jsem se na svém počítači nasimulovat práci čtyř uživatelů s webovým fotoalbem, které jsme vytvořili v minulých dílech. Použil jsem testovací program JMeter, opět z rodiny projektů Jakarta Apache. Cocoon běžel na mém domácím počítači (Duron 1G2, 384 MB RAM) pod implicitně dodávaným servletovým kontejnerem Jetty verze 4.2.9. JMeter běžel na tomtéž počítači. Uživatelé náhodně požadovali buď stránku s albem, nebo některou stránku s fotografií. Časový interval mezi „kliknutím“ každého uživatele byly dvě sekundy (čili Cocoon byl zatěžován přibližně dvěma požadavky za sekundu).
Výsledky ukazují, že odezva na první požadavek každého uživatele byla několik vteřin. Zde došlo pravděpodobně k překladu XSP, vytvoření náhledů a jejich kešování. Další požadavky jsou vyřízeny převážně za méně než 250 ms. Zde je záhodno uvést, že značnou část doby vyřízení požadavku zabere přenos obrázků. Pokud se v JMeteru přenos obrázků vypne, doba odezvy se pohybuje okolo padesáti až šedesáti milisekund. Chcete-li s měřením experimentovat sami, můžete použít pro JMeter skript, který najdete v souboru jmeter-cocoon.zip.
Výše uvedené měření není patrně možné příliš zobecňovat. Platí jen v uvedeném kontextu. Nicméně se nezdá, že zpracování krátkých XML souborů s jednou nepříliš komplikovanou XSL transformací představuje výkonnostní riziko webové aplikace v Cocoonu. Nakonec bych se ještě chtěl zmínit o tom, že naše fotoalbum nebylo navrhováno na maximální efektivitu a rychlost. Mělo spíše ilustrovat základy Cocoonu jako frameworku pro publikování na webu a webové aplikace. Dá se říci, že z hlediska efektivity by se na něm dalo vylepšit téměř vše. Nejméně efektivní je však dynamická transformace obrázků do náhledů. Z hlediska výkonu je to zbytečná a přitom dosti drahá operace nad statickými obrázky.