cache
Příkaz vyznačující fragment šablony, jehož výstup se má uložit do obsahové cache. Místo dalších vyhodnocení se bude používat hodnota z cache.
cache
[ cache-options ] statement-body/cache
- cache-options
-
Nastavení parametrů cache, pokud její defaultní chování nevyhovuje prezentační logice nebo není optimální. Možnosti zahrnují:
- nastavení vlastní sady klíčů cache,
- nastavení časové platnosti cache,
- selektivní vypnutí cache na základě dynamicky dopočítané hodnoty.
- statement-body
- Fragment šablony, jehož výstup se má ukládat do cache a pak z ní načítat.
Pokud je cache nastavená korektně, měla by z pohledu autora šablony fungovat zcela transparentně. To znamená, že by se šablony měly vyhodnocovat stejně, jako by se každý výskyt příkazu cache
nahradil svým tělem (statement-body). Jediným efektem použití příkazu by mělo být zrychlení výpisu a snížení zátěže prostředků potřebných pro vyhodnocení šablony.
{cache}
{while _primary!newsSource forceCount=1 limit=30}
{_.asset mode="newsOneliner"}
{whilelast}
<p>{xlat("news.total", null, _count)}</p>
{/whilelast}
{/while}
{/cache}
{while _primary!newsSource forceCount=1 limit=30}
{_.asset mode="newsOneliner"}
{whilelast}
<p>{xlat("news.total", null, _count)}</p>
{/whilelast}
{/while}
V obou případech bude výstup týž. Rozdíl je jen v efektivitě opakovaného vyhodnocování šablony.
Příkazy cache je možné používat vnořené, a to i přes hranici jedné šablony. Pak platí, že do obsahové cache se uloží pouze hodnota výstupu příkazu na nejvyšší úrovni, který není selektivně vypnutý.
Podrobnější popis fungování
Každý výskyt příkazu je spjatý s nějakým klíčem. Klíč je daný mapou hodnot. Hodnoty tvořící klíč jsou dané buď implicitně, nebo jsou explicitně zadané při volání příkazu.
Při vyhodnocování příkazu se nejprve zjistí, zda pro daný klíč existuje verze fragmentu v cache.
- Pokud ano, použije se tato verze; tělo příkazu se tedy už vůbec nevyhodnocuje.
- Pokud verze fragmentu neexistuje, tělo příkazu se normálně vyhodnotí a použije se vyhodnocená verze; tato verze se zároveň uloží v cache pro daný klíč.
Invalidace
- Pozor na použití parametrů invalidationDisabled a oldVersionLifetime zároveň
- V dokumentaci je popsáno chování, které zatím neodpovídá skutečnosti
- Momentálně se po publikaci se invalidují i fragmenty s parametrem invalidationDisabled
- Fix je připraven pro Vetis a bude portován do ostatních větví
- Použití parametru invalidationDisabled ovlivňuje i chování na editu
Platnost všech fragmentů uložených v obsahové cache končí v okamžiku, kdy se změní libovolný asset v assetové databázi. Vedle toho také může skončit po uplynutí doby, kterou stanovil autor šablony.
Omezené používání neplatných fragmentů
Od verze 3.4.45 (při určité konfiguraci cache na straně aplikace) je možné stanovit dobu, po kterou je možné používat i verze fragmentů, jejichž platnost už skončila. Slouží k tomu parametr oldVersionLifetime
; jeho hodnotou je doba trvání zadávaná ve stejném tvaru jako u parametru interval
; hodnota 0 je výchozí a deaktivuje funkci.
Položky cache, které mají tento parametr nastavený, se při běžné změně databáze nesmažou, ale pouze označí jako zastaralé. To umožňuje za určitých okolností paralelní zpracování, kdy jedno vlákno generuje nový obsah a ostatní vlákna mezitím dostávají starý obsah z cache. Hodnota parametru udává maximální dobu, po kterou se může starý obsah ještě používat.
Potlačení invalidace
Od téže verze 3.4.45 (opět, při určité konfiguraci cache na straně aplikace) je možné částečně potlačit invalidaci spjatou se změnami v assetové databázi: slouží k tomu booleovský parametr příkazu invalidationDisabled
.
(Některé změny nadále budou způsobovat odstranění fragmentu z cache: uzavření projektu – tedy věc, která nastává jen na editačním serveru – povede k odstranění fragmentů vázaných na tento projekt; také vynucená invalidace a naplnění kapacity cache způsobí odstranění položek. Položka naopak zůstane v cache i po restartu serveru.)
Použití parametru je vhodné kombinovat s parametrem interval
, aby se omezilo maximální stáří dat.
Tento parametr je nutné používat s velkou rozvahou a jako krajní prostředek: Striktně vzato by mělo jít jen o případy, kdy zobrazovaná data žádným způsobem nezávisejí na obsahu assetové databáze.
Klíč cache
Je třeba vzít na vědomí, že verze cachovaných fragmentů je možné sdílet, a to jednak mezi požadavky s různou URL, ale také mezi různými výskytu příkazu cache v rámci jedné šablony nebo dokonce i mezi šablonami. Zatímco první možnost, pokud se provede správně, zvýší efektivitu využití cache, druhých dvou je obecně třeba se vyvarovat.
Proto je třeba věnovat pozornost klíčům identifikujícím fragmenty výstupu v cache. Každý klíč identifikuje právě jeden fragment.
Výchozí složení klíče
Výchozí klíč je tvořený následujícími položkami:
- identifikace uživatele (viz dále),
template
- aktuální šablona,site
- aktuální prezentace,me
- renderovaný pagelet,main
- hlavní obsahový asset,section
- primární sekce,format
- aktuální formát,mode
- aktuální režim,language
- aktuální jazyk.
Přidání vlastních položek do klíče
Vlastní položky lze přidat ve tvaru "jméno = hodnota" v libovolném počtu. Typy hodnot jsou omezené na primitivní typy jazyka Java a typy String, Date a Asset.
Položky je třeba přidat vždy, když by defaultní sada hodnot nestačila ke generování unikátních klíčů pro různé verze fragmentů. Typické případy jsou:
- dva a více cachovaných bloků v jedné šabloně,
- výpis závislý na parametrech URL,
- výpis závislý na uživatelském nastavení, cookies apod.
{cache cblock=1}
{_template.header}
{/cache}
{value(_main, _primary)}
{cache cblock=2}
{_template.footer}
{/cache}
Pokud jsou v jedné šabloně dva a více bloků ukládaných do obsahové cache, je potřeba zajistit, aby neměly stejný klíč v cache.
Zde se toho dosáhne přidáním položky cblock
s různými hodnotami do klíče.
Odstranění výchozích položek z klíče
Použitím parametru OVERRIDE
(bezhodnotový) se odstraní všechny výchozí položky z klíče. Tento parametr by měl být uvedený jako první v pořadí parametrů příkazu. Typicky je pak třeba některé z výchozích položek do klíče znovu přidat.
Počet verzí fragmentu v cache můžeme odhadnout součinem počtů různých hodnot pro každou položku, vstupující do klíče cache. Odstraněním jedné položky z klíče tedy obecně zvýšíme efektivitu využití cache. Podmínkou je, aby na různých hodnotách položky nezávisela verze fragmentu.
{cache OVERRIDE template=_template site=_site format=_format language=_language}
{_template.mainMenu}
{/cache}
V tomto případě můžeme předpokládat, že hlavní menu je shodné pro celou prezentaci a jeho podoba záleží jen na jazyce. Proto je mezi klíči ponechán jazyk. Ostatní klíče, které jsou znovu zavedeny, je rozumné uvést s ohledem na možné kolize s jinými fragmenty v cache.
Vždy je nutné mít v klíči aktuální šablonu – předejdeme tím kolizím s dalšími bloky ukládanými do cache z jiných šablon. Pokud je vaše prezentační logika navržená tak, že může sdílet fragmenty v cache mezi různými šablonami, je pravděpodobné, že porušuje princip DRY.
Pokud zvažujeme vynechání položky klíče, u které předpokládáme jen jednu možnou hodnotu (například když předpokládáme jen jediný formát: "html"), je užitečné tuto hodnotu ponechat v klíči.
- Pokud je předpoklad o jediné možné hodnotě splněný, efektivita využití cache se tím nezhoršuje: nevznikají nové verze fragmentu uložené samostatně.
- Praxe ukazuje, že pokud by předpoklad nebyl splněný v některých okrajových případech, vedlo by vynechání položky k obtížně laditelným chybám.
Identifikace uživatele
Systém počítá s tím, že stránka může mít jiný obsah podle toho, jaký uživatel tuto stránku zobrazuje. Parametr storeMode
určuje, jakým způsobem se bude zohledňovat identita uživatele systému jNetPublish . Možné hodnoty jsou:
- application
- Identita uživatele se ignoruje (default).
- roleDiggest
- Do klíče se uloží souhrn ACL rolí uživatele. Tedy pro všechny uživatele se stejnými rolemi bude obsah v cache uložen pouze jednou.
- user
- Do klíče se uloží ID uživatele.
Časová platnost
Pro nastavení časové platnosti je možné použít parametr interval
.
Parametr příkazu interval
: jeho hodnotou je počet sekund, po které se uložené fragmenty pokládají za platné. Fragment, jehož platnost skončila, se už nepoužije, při dalším požadavku se bude generovat znovu a zobrazení stránky bude čekat na jeho vygenerování.
Pro usnadnění zadávání je možné použít řetězec obsahující čísla a následující modifikátory:
d
- Číslo před modifikátorem se chápe jako počet dní.
h
- Číslo před modifikátorem se chápe jako počet hodin.
m
- Číslo před modifikátorem se chápe jako počet minut.
s
- Číslo před modifikátorem se chápe jako počet sekund.
Kdekoliv v parametru interval se může vyskytovat mezera, která je ignorována. Například: '1 0s' je 10 sekund, '2m 5' je 125 sekund, '1h3s' je 3603 sekund a podobně.
{cache interval="1h"}
<table>
{while _template.sqlSource}
<tr>
<th>{_.product_name}</th>
<td>{_.product_price}</td>
</tr>
{/while}
</table>
{/cache}
Defaultní klíč cache není žádným způsobem spjatý se změnou obsahu databáze, ze které se zobrazuje obsah. Jako určitá aproximace řešení tohoto problému se může použít časové omezení platnosti cache, například na jednu hodinu.
Selektivní vypnutí
Příkaz může mít parametr DISABLED
. Pokud je jeho hodnota true
, cache se nepoužije.
{cache DISABLED=in("noCache", _primary.controlWordsSet)}
{_template.header}
{value(_main, _primary)}
{_template.footer}
{/cache}
Daný fragment šablony bude ukládán do cache, pokud aktuální primární sekce nemá nastavené řídící slovo "noCache". Vypnutí cache se tedy takto může provádět v rámci nastavení struktury prezentace.
Jak příkaz používat
Je těžké zformulovat nějaká jednoznačná kritéria, která by bylo možné bez dalšího automaticky uplatnit. Použití obsahové cache musí vždy být reakcí na pozorovaný výkonnostní problém a testy musejí prokázat jeho účinnost.
Co dodržovat
Aby se snížila samotná režie cache a aby údržba cache nebyla pro autora šablon zbytečně náročná, dodržujte následující pravidla:
- spojujte sousední cachované bloky,
- cache používejte ve volající šabloně, ne v šabloně volané,
- vynechávejte defaultní hodnoty z klíče, jen když to má opravdu smysl,
- parametry příkazu
cache
nemá smysl složitě počítat.
Limity použití
- Při prvním požadavku fragment není v cache. Čili pokud se domovská stránka načítá půl minuty, obsahová cache vám nepomůže.
- "Opatrná" invalidace: invaliduje se s každou změnou každého assetu, i když se asset nepodílel na sestavení fragmentu v cache. Toto je třeba brát v úvahu při nastavování režimu práce se systémem jNetPublish: omezení počtu publikací (například prací v projektu) povede také ke snížení počtu invalidací cache.
- Obtížná predikovatelnost chování: závisí na nastavení systému jNetPublish, serveru, operačního systému, nad kterým běží. Proto je potřeba použití vyvodit z výsledků výkonových testů a korektnost zpětně opět otestovat.
Indikace
S ohledem na předchozí lze jen volně nastínit, kdy se typicky bude cache používat:
- velká návštěvnost: desítky a stovky požadavků za sekundu,
- velké množství relevantních assetů: stovky a tisíce assetů, a to jak assetů přímo vypsaných, tak assetů, které musí kontrolovat dotazový zdroj,
- operace zdokumentované jako výkonově náročné.
V dalších případech je možné cache dočasně uplatnit, ale pokud nastanou, svědčí to spíš o špatném návrhu:
- v šabloně se provádí složitý výpočet,
- zobrazují se data z aplikace, která nemá vlastní cache.
Kontraindikace
- Výpis dat jednotek assetů nemá smysl ukládat do obsahové cache. Data budou typicky uložená v cache vrstvy zajišťující perzistenci assetů (PAL), šlo by tedy o zbytečné dublování funkčnosti.
- Aplikace poskytující data by měla mít vlastní cache. V tom případě bude pravděpodobně navržená tak, aby fungovala v souladu s životním cyklem zobrazovaných dat, a výsledky cache aplikace tedy budou nutně lepší.