Keš / Cache

A když už víte vše o Jet MVC, tak nám zbývá poslední téma a to keš. Sem tam jsme už o toto téma zavadili, ale je jasné, že je to důležité. Tak si vše již vyřčené zopakujeme téma rozebereme víc do detailů.

Co se do keše ukládá?

Do keše si Jet MVC ukládá tato data:

  • Mapa bází
    Je to asicoované pole, které umožní rychle identifikovat o jakou bázi a lokalizaci se jedná a je možné se vyhnout neustálému prohledávání definic bází.
  • Mapy stránek
    Jsou to asociovaná pole dat ukládaná pro každou bázi a lokalizaci zvlášť. Co přesně v mapách je je věcí vnitřní implementace (ale nic vám samozřejmě nebrání nahlédnout do dat i zdrojáků). Cílem je vyhnout se opakovanému prohledávání definic stránek a minimalizovat množství I/O operací a potřebného času.
  • Statický (kešovatelný) obsah stránek
    Jak již víte, tak obsah stránek může definovat že je kešovatelný. Takový obsah se vygeneruje jednou a pak se zaznamená do keše (pochopitelně pokud je keš aktivní) a při dalším průchodu není vůbec nutné provádět dispatching - tedy volat akci kontroleru.

Platnost záznamů v keši je dána pouze tím kdy se keš MVC devaliduje / vyresetuje.

Co mohu vřele doporučit je nespoléhat pouze na keš MVC a řešit si další úroveň keše na úrovni kontrolerů (a modulů) a to vždy dle situace, s promyšlením celé architektury vaší aplikace. A také je možné implementovat keš, která zaznamenává celé vygenerované statické stránky. To jsou věci, které jsou v praxi úzce spjaté s požadavky konkrétního projektu a je to tedy na vás a na vaší invenci. Ovšem nebojte se tu keš co Jet MVC již má používat. Umí toho vyřešit opravdu mnoho. Ale zároveň se prosím nedomnívejte, že je to všespásné. Poslední slovo má vždy profiler, zátěžové testy a vaše zkušenosti.

Kontext keše

O tom již byla zmínka zde. Ale vůbec není od věci to zde zopakovat a trochu rozvést.

Popíšeme si to na konkrétní situaci a to na kapitole dokumentace, kterou právě teď čtete.

O zobrazení tohoto textu se postaral modul Web.Doc.Browser, který na základě části URL našel tuto kapitolu. Následně meta informace v textu článku nahradil normálními odkazy na ostatní kapitoly, naformátoval ukázkové kusy kódu, nastavil drobečkovou navigaci i kontextové menu. Prostě provedl opravdu dost operací, které by ale bylo nutné provádět zas a znovu a to zcela zbytečně, protože pokud dokumentaci nikdo neupraví, bude výsledek stále tentýž.

Ovšem všechny pozice pro které modul vygeneroval obsah jsou označené jako kešovatelné. To znamená, že tuto práci bude modul dělat pouze jednou (tedy do té doby, než někdo v administraci dokumentaci pozmění a keš se devaliduje).

To je vše jasné. Ale je tu jeden háček. Pro všechny kapitoly dokumentace je z hlediska Jet MVC v tomto webu jedna stránka. A statický obsah ukládaný do keše musí být nějak jednoznačně identifikován. Pro identifikaci je k dispozici ID báze, kód lokalizace, ID stránky a také klíč identifikující konkrétní obsah stránky. Ovšem tyto údaje jsou společné a totožné pro všechny kapitoly dokumentace. Tedy takto jednoduše by to nefungovalo, protože jeden záznam v keši by byl platný pro celou dokumentaci a mohli by jste se kouknout na jakoukoliv URL jakékoliv kapitoly, ale obsah by byl stále stejný ...

Z toho důvodu musí příslušný kontroler aplikačního modulu Web.Doc.Browser udělat během resolv procesu jednu klíčovou věc. Říct stránce jaký má keš kontext. V tomto konkrétním případě na který právě koukáte to udělá takto: MVC::page()->setCacheContext( static::$article_id );

A od této chvíle se kontext (zde ID článku dokumentace, ale může to být cokoliv jiného) stává součástí klíče pro načítání a ukládání dat z a do keše.

POZOR! Zmínil jsem, že kontext se nastaví během provádění resolv. Tato informace nesmí vyznít jako okrajová. Naopak je to velice důležité. Resolv se totiž provádí vždy právě z důvodu aby bylo možné správně nastavit kontext keše. Jinak by logicky nebylo možné keš ani správně načíst. Proto je důležité mít v kontroleru dobře optimalizovaný i resolv proces (metodu resolv() ).

Když už jsem jako příklad uvedl tuto dokumentaci, tak doplním, že tuto situaci řeším samostatným uložením mapy ve které jsou URL článků a jejich ID. Taková jednoduchá mapa ani nemusí být v databázi, ale stačí ji uložit do adresáře ~/application/data/ a není pak ve finále nutné provést ani jeden SQL dotaz (když je keš zahřátá - pochopitelně)

Jak to uděláte vy je pochopitelně na vás ;-)

Inicializace keše

Inicializaci MVC keše najdete ve skriptu ~/application/Init/Cache/MVC.php. Pro názornost si ukážeme jeho podobu: namespace JetApplication;

use 
Jet\MVC_Cache;
use 
Jet\SysConf_Path;

use 
Jet\MVC_Cache_Backend_Files;

require_once 
SysConf_Path::getLibrary() . 'Jet/MVC/Cache/Backend/Files.php';
$backend = new MVC_Cache_Backend_Files();


/*
use Jet\MVC_Cache_Backend_Redis;

require_once SysConf_Path::getLibrary().'Jet/MVC/Cache/Backend/Redis.php';
$backend = new MVC_Cache_Backend_Redis();
*/

MVC_Cache::init$backend );

Jek je pro Jet typické, tak je opět použita strategie přes vložení závislosti. Vytvoříte instanci požadovaného backendu a tu předáte fasádě, která se o keš stará a plní tedy roli kontejneru. Všimněte si, že zde se opět ještě nepoužívá Autoloader, ale je použito konvenční require.

Zapnutí / vypnutí keše

V systémové konfiguraci Jet slouží pro zapnutí a vypnutí třída Jet\SysConf_Jet_MVC a metody setCacheEnabled a getCacheEnabled.

Nastavení se provádí ve skriptu ~/application/config/Jet.php.

Backend - interface Jet\MVC_Cache_Backend a třída Jet\MVC_Cache

Pojďme se kouknout jaké má mít backend rozhraní. Samozřejmě si můžete vyvíjet své backendy. Implementovat toto rozhraní je jediná podmínka.

Idenetické rozhraní (ve smyslu stejných tříd - pouze statických) má i fasáda a kontejner, třída Jet\MVC_Cache. To je třída přes kterou Jet s MVC s keší pracuje.

Metoda Význam
public isActive(
): bool
Indikuje zda je keš aktivní.
Musí zohlednit systémovou konfiguraci.
Krom konfigurace musí zohlednit technické ohledy zda je keš technicky dostupná a použitelná.
public reset(
): void
Devaliduje keš. Pozor! Mělo by fungovat i když je keš vypnuta systémovou konfigurací.
public loadBaseMaps(
): array|null
Nahraje mapu bází.

Pokud keš není aktivní, nebo neobsahuje potřebná data, pak vrací null.
public saveBaseMaps(
array $map
): void
Uloží mapu bází.

Pokud keš není aktivní, pak nic neprovádí.
public loadPageMaps(
MVC_Base_Interface $base,
Locale $locale
): array|null
Nahraje mapy stránek pro danou bázi a lokalizaci.

Pokud keš není aktivní, nebo neobsahuje potřebná data, pak vrací null.
public savePageMaps(
MVC_Base_Interface $base,
Locale $locale,
array $map
): void
Uloží mapy stránek pro danou bázi a lokalizaci

Pokud keš není aktivní, pak nic neprovádí.
public loadContentOutput(
MVC_Page_Content_Interface $content
): string|null
Pokud je keš aktivní, tak nahraje pro obsah a kontext dříve vygenerovaný výstup (kus HTML, textu, XML, ...).

Pokud keš není aktivní, nebo neobsahuje potřebná data, pak vrací null.
public saveContentOutput(
MVC_Page_Content_Interface $content,
string $output
): void
Pokud je keš aktivní, tak uloží pro daný obsah a kontext jeho výstup (kus HTML, textu, XML, ...).

Pokud keš není aktivní, pak nic neprovádí.

Předpřipravené backendy

Backend Popis
Jet\MVC_Cache_Backend_Files Základní backend, který data ukládá v podobě PHP souborů do adresáře ~/cache/.

Pro běžné a základní použití dostačující.

Využívá nízkoúrovňový backend Jet\Cache_Files.
Jet\MVC_Cache_Backend_Redis Zejména pokud již potřebujete provozovat aplikaci na více serverech, nebo z jiného důvodu už prostě ukládání do souborů nestačí, tak máte možnost použít Redis.

Využívá nízkoúrovňový backend Jet\Cache_Redis.
Předchozí kapitola
Jet\MVC_Layout_OutputPostprocessor
Další kapitola
Jiné (zjednodušené) přístupy k MVC