spájame
slovenskú
IT komunitu
pridaj sa
Registrácia · Login

Matúš Koprda 14.2.2011, článok je súčasťou seriálu Ako sa stať PHP ninja s Yii Frameworkom
Hodnoť článok:
1 0

Yii Framework: Zvyšujeme rýchlosť s cache

Pokračujeme našim seriálom o programovaní v Yii frameworku. Už sme si povedali ako zvýšiť vlastnú produktivitu pri písaní aplikácií, teraz si ukážeme ako zvýšiť rýchlosť aj serveru.

Predpokladám, že viac menej všetci vedia čo je cache, ale pre úplnosť iba pár vetami... Predstavte si nejaký blog so všetkými časťami - header, články, info o autorovi na boku, možno nejaký výber článkov a pár iných srandovných okienok. Väčšina z týchto prvkov sa mení raz za čas a bolo by zbytočné pre každého navštevníka zložito generovať znova to isté. Cache je dočasná pamäť, kde si odložíme vygenerovanú stránku (alebo jej časti) a namiesto generovania budeme iba vypisovať obsah cache až pokým sa niečo nezmení alebo nevyprší platnosť.

Yii má cacheovanie celkom fajn prešpekulované. Dáva nám na výber z troch spôsobov ako používať cache v kóde a podporuje niekoľko typov cacheovacích systémov s možnosťou jednoducho si dorobiť vlastný. Od obyčajného ukladania cacheovaného obsahu do súborov alebo do databázy až po sofistikovanejšie systémy ako sú XCache, Memcache, EAccelerator a Wincache.

Cache sa zapína zase raz v configu (/protected/config/main.php) v sekcii components tak, že dopíšete:

'cache'=>array(
	'class'=>'CFileCache',
),

Namiesto CFileCache môžete použiť aj triedy pre vyššie spomínané systémy CDBCache, CXCache, CMemCache, CEAcceleratorCache alebo CWinCache. V prípade Memcache môže byť potrebné dopísať dodatočné nastavenie pre server. Špeciálny typ je CDummyCache, ktorý sa len tvári, že je cache, ale v skutočnosti nič neukladá, čo je dobré v situácií keď potrebujete cacheovanie dočasne vypnúť.

Využívanie cache je pre programátora transparentné, t.j. nezávisí od používaného systému a tým pádom ho môžete kedykoľvek v configu zmeniť bez následkov.

Cacheovanie dát

Najzákladnejším spôsobom, na ktorom sú postavené ostatné, je uloženie nejakého stringu do cache. Využiteľné je to napríklad ak si chceme uchovať výsledok náročnej query. Na manipuláciu s cache máme dostupné metódy get(), set(), add(), delete() a flush().

Set() uloží daný string do cache a nastaví podmienku kedy údaje prestávajú byť platné a musia sa obnoviť. Podmienkou môže byť čas, zmena výsledku databázovej query, akýkoľvek PHP výraz, atď. Jednotlivé položky cache musíme vedieť odlíšiť, takže je na nás, aby sme poskytli nejaké unikátne ID ('tabulka_dristov' a podobne).

// táto hodnota zostane v cache až kým ju nevymažeme
Yii::app()->cache->set($id, $hodnota);

// v tomto prípade by nastavená hodnota prestala platiť po 60 sekundách
Yii::app()->cache->set($id, $hodnota, 60);

// hodnotu obnovíme len ak sa zmení čas modifikácie príspevku v databáze
Yii::app()->cache->set($id, $hodnota, 0, new CDbCacheDependency("SELECT lastModification FROM posts WHERE id_post = 10"));

Okrem závislosti na hodnote v databáze môžeme cache naviazať na zmenu súboru (CFileCacheDependency), zmenu PHP výrazu, na viac závislostí naraz (CChainedCacheDependency) a ďalšie udalosti.
Alternatívne je k dispozícii aj metóda add(), ktorá uloží hodnotu len ak sa položka s daným id ešte nenachádza v cache.

Get() vráti buď uloženú hodnotu, alebo false pokiaľ hodnota neexistuje v cache alebo je neplatná.

$hodnota = Yii::app()->cache->get($id);
if ($hodnota === false)
{
    Yii::app()->cache->set($id, uplneZeMegaNarocnyVypocetHodnoty(), 600 );
}

V prípade, že by sme sami chceli vymazať položku z cache, použijeme delete($id) alebo dokonca flush(), ktorý vymaže celú cache (pri niektorých systémoch naozaj celú vrátane údajov iných aplikácií!). Delete() je užitočný v prípadoch, kde presne viete kedy cache prestáva byť platná (pridá sa komentár a podobne).

Fragmenty

Druhým, o niečo praktickejšim spôsobom ako používať cache, sú fragmenty. Používajú sa priamo vo viewoch na ukladanie kúskov kódu (kľudne aj celej stránky). Praktickejšie sú hlavne z dôvodu, že ponúkajú "variácie". V určitých prípadoch môže vyzerať stránka pre rôznych používateľov inak - napríklad každému sa musí zobraziť vlastný profil a keby nepoužívame variácie, všetkým používateľom by sa zobrazil profil toho používateľa, pri ktorom sa akurát obnovovala cache. A to by nebolo dobré. :p

Pre každého používateľa by bol tento fragment cacheovaný zvlášť.

<?php
if($this->beginCache($id, array('duration' => 3600, 'varyBySession' => true ))) { ?>
	<p><strong>Nasleduje masívny query:</strong> <?php echo masivnyQuery(); ?></p>
<?php $this->endCache(); } ?>

Môžme používať aj dependencies:

<?php
if($this->beginCache($id, array('varyByParam' => array('id'), 'dependency' => array(
        'class' => 'CDbCacheDependency',
        'sql' => 'SELECT lastModification FROM articles WHERE id_article = 10') ))) { ?>
	Cacheovaný článok
<?php $this->endCache(); } ?>

Formuláre cacheujeme iba pri GET requeste. Pri POSTe sa zobrazuje formulár, ktorý neprešiel validáciou.

<?php
if($this->beginCache($id, array('requestTypes' => array('GET')))) { ?>
<form ...>
	blabla
</form>;
<?php $this->endCache();

Okrem varyByParam (cache sa ukladá zvlášť pre každú kombináciu GET parametrov) a varyBySession (pre každého používateľa zvlášť) môžeme ešte využiť výrazy varyByExpression (vyhodnotí sa PHP kód) a varyByRoute (cache bude pre každú cestu controller/akcia zvlášť). Ak fragmentu nenastavíme duration, jeho predvolená hodnota bude 60 sekúnd (pre porovnanie, pri cacheovaní dát je defaultná platnosť 0, čiže kvázi do nekonečna).

Stránky

Najvyššiou úrovňou cacheovania v Yii sú celé stránky. Narozdiel od fragmentov, kde sme mohli ukladať nanajvýš celý view, ukladá tento typ cacheovania aj rozloženie/layout stránky a obchádza dokonca akciu v controlleri, takže je s prehľadom najrýchlejší. To je samozrejme za cenu o niečo menšej flexibility, ale na statické stránky je to ideálne. Ušetriť sa dá aj na dynamických stránkach, ktoré sa nemenia až tak často. Napríklad ani na veľmi frekventovanom fóre si prakticky nikto nevšimne ak budete stránku obnovovať každých 30 sekúnd a vy ušetríte strašnú kopu výkonu.

Cache celej stránky sa aktivuje v controlleri pomocou filtrov (príklad je z controlleru SiteController.php z dema).

public function filters()
{
	return array(
		array(
			'COutputCache - captcha, cachetest',
			'duration'=>60,
			'requestTypes'=>array('GET'),
			'varyByParam=>array('language'),
		),
	);
}

Filtrov môžete mať viacej, preto sú parametre obalené v dvoch poliach. Prvý parameter udáva filter, ktorý sa má použiť (v tomto prípade COutputCache), zmanienko a akcie na ktoré platí. V prípade, že by bolo znamienko plus, filter by sa použil iba na definované akcie, ak by bolo mínus, použije sa na všetky okrem definovaných akcií. Zvyšné parametre sú dostupné také isté ako s fragment cache.

Kvôli i18n treba na stránkach odlišovať jazyk a keďže sme internacionalizáciu v minulom tutoriále výborne spravili:), stačí zapnúť variáciu podľa GET parametra 'language'. Navonok síce aplikácia vyzerá, že jazyk nie je v GET, ale interne sa URL adresa tak sparsuje.

Dynamický obsah

Keby sa musí každá stránka cacheovať zvlášť pre každého používateľa kvôli drobnej lolovine typu "Ste prihlásený ako Ján Gule", cache by úplne stratila význam. Preto umožuje Yii pridávať do fragmentov (a celých stránok) dynamický obsah.

<?php if($this->beginCache($id)) { ?>
    <?php $this->renderDynamic($callback, $parameter1, $parameter2, ...); ?>
	Niečo nedynamické...
<?php $this->endCache(); } ?>

$callback môže byť statický PHP callback, názov metódy aktuálneho controllera (čiže zavolá sa $this->nazovMetody()) alebo názov globálnej PHP funkcie. "Najčistejšie" je väčšinou použiť druhý spôsob. Pozor si treba dať ak máte nejaký dynamický obsah priamo v layoute. Vtedy je potrebné metódu doplniť do globálneho controllera, od ktorého sa dedia všetky ostatné controllery. Nájdete ho v /protected/components/Controller.php. V demo aplikácii sa takto generuje menu, keďže práve v ňom je informácia o prihlásení.

Nárast rýchlosti + demo

Dosť dôležitou otázkou je koľko výkonu vlastne ušetríme a či sa nám oplatí komplikovať život s cache. V prvom rade, pokiaľ nemáte (alebo neočakávate) relatívne vysokú návštevnosť (v špičke aspoň pár requestov za sekundu), nad cache netreba ani rozmýšlať. Podľa mojich testov trvalo generovanie plne cacheovanej stránky do 30ms (bez akýchkoľvek akcelerátorov kódu). Rozdiel vo výkone sa tým viac prehlbuje, čím komplikovanejšie je generovanie stránky. Samozrejme sa môžete vykašlať aj na stránky, ktoré sa síce dlho generujú, ale používajú sa zriedkavo.

Opäť si môžete stiahnuť demo aplikáciu obsahujúcu aj kód z predchádzajúcich tutoriálov: Yii Cache demo [rar]
Pred spustením treba naimportovať údaje do DB (sql.html) a nastaviť k nej prístup v configu (protected/config/main.php).

* * *

Ak by ste nabudúce chceli vidieť nejakú špecifickú tému, napíšte do commentov pod tento článok alebo mail na 8 zavináč brm.sk. Ak sa vám náš tutoriál páči, tak viete, čo máte robiť...

Matúš Koprda Matúš Koprda

Momentálne robím internety a keď budem veľký, snáď sa dostanem aj k hrám alebo niečomu zmysluplnému. :) Mám rád minimalizmus, obskúrnu hudbu, všetko geeky a rýpanie sa v detailoch. Ďalšie kecy odo mňa nájdeš na brm.sk a na Twitteri @blade_sk.


Hodnoť článok:
1 0

1 komentár k článku:

Komentovať môžu iba prihlásení

Zaregistruj sa cez bezplatnú registráciu alebo použi login cez Facebook (FB Connect)

Prihlás sa tu, ak už máš profil na Zajtra.sk:


Zabudol som heslo

0 0 Michal Belianský (fb) 22.6.2011 00:00:00
dobrý deň prajem, bude táto sekcia ešte pokračovať?
Zajtra.sk > Programovanie > PHP > Yii Framework: Zvyšujeme rýchlosť s cache


Kritika

Vieš ako robiť veci lepšie? Pomôž našim odvážnejším členom a skritizuj im projekty!

Reklama

Seriály zo Zajtra.sk

Reklama