GZip, cache a urychlení web prezentací
Provozujete-li nějakou prezentaci s vysokou návštěvností, brzy dospějete k závěru, že dynamicky generované stránky nejsou to pravé, neb dochází k duplicitním dotazům na databázi, s jejichž výsledky se provádí neustále ty samé operace. PHP sice nabízí Output control nástroje, které automaticky realizují jak cachování mezivýsledků, tak GZip kompresi. Má zkušenost však byla, že se nástroj choval nedeterministicky a rozhodně ne, tak jak jsem si představoval. Takže tudy ne.
Dospěl jsem k závěru, že bude nejlepší vytvořit jakýsi stínový server, který bude na žádost návštěvníků poskytovat nacachované a GZipem sbalené stránky a to přesně dle definovaných pravidel.
1 přečti URL adresu a podívej se do cache, zda je soubor k URL náležející obsažen
1-1 soubor obsažen je
1-1-1 pokud je aktualizace souboru delší než 24 hodin, nebo byla zaslána žádost o aktualizaci, proveď bezpodmínečně krok 1-2
1-1-2 pokud je soubor aktuální, předej jej dle podpory GZip v prohlížeči návštěvníkovi a pokračuj krokem 2
1-2 soubor obsažen není, dotaž se dynamického serveru na dostupnost daného souboru
1-2-1 soubor je nedostupný, vrať chybu 404 a k ní náležící informační stránku, pokračuj krokem 2
1-2-2 soubor je dostupný, ulož jej do cache, odstraň z něj přebytečné bílé znaky a komentáře a sbal jej formátem gzip. Pak proveď bezpodmínečně bod 1-1-2.
2 vymaž všechny dočasné nebo neaktuální použité soubory v cache
Následně vyvstala otázka jak řešit návštěvníkem realizované operace, které mají vliv na obsah stránek. Dost věcí lze moc hezky řešit přes AJAX – například máte-li vlastní počítadlo, stačí jej umístit do zvláštního souboru a ten AJAXem volat. Například takto:
function entries() {
if( typeof XMLHttpRequest != 'undefined' ) {
var httpRequest = new XMLHttpRequest();
httpRequest.open( 'GET', '/counter.php', false );
httpRequest.send( null );
document.getElementById( 'results' ).innerHTML = httpRequest.responseText;
}
}
V dokumentu poté vytvoříme třeba nějaký span s id=”results”, do kterého nám může počítadlo vracet informace o počtu návštěvníků. Není nic snažšího potom takovouto funkci volat z body onload. Další výhodou takovéhoto počítadla je fakt, že přes něj neprojdou boti.
Ohledně zasílání názorů do příspěvkových diskusí, stačí stínový server přizpůsobit, aby předával data zaslaná POSTem dynamickému serveru a aby stránku, na níž byl POST zaslán, označil “k aktualizaci” (označení k aktualizaci jsem implementoval funkcí touch, kterou nastavím poslední aktualizaci souboru na delší než 24 hodin, na což algoritmus reaguje aktualizací).
Další věcí, která může usnadnit podobné implementace je Google search API, které umožňuje vyhledávání plně na bázi AJAXu. Rychlé, výsledky jsou relevantnější než XML API nabízíné Yahoo, a hlavně není nutná žádná účast na straně Vašeho serveru.
Takto jsem realizoval stínový server na Ekonomicko-správní fakultě. Pokud by někdo z Vás nahlédl, doporučuji podívat na informaci “O této stránce” v patičce, která je generována právě výše zmíneným způsobem.
A závěry? Konkrétně web ESF navštíví denně v průměru 716 návštěvníků denně a každý otevře asi 8 stránek po zhruba 11KiB. GZipování ušetří asi 66 % přenesených dat, což v tomto případě dělá kolem 40MiB denně. A strojový čas? Dynamické generování stránek trvá v rozmezí od 0,080 do 0,250 s – v závislosti na složitosti stránky a počtu aktuálních návštěvníků. Poskytnutí stránky z cache trvá VŽDY 0,002 s. Denně tak dojde k ušetření 14 minut strojového času, což není sice hodnota nijak významná, ale na rychlosti poskytování stránek se téměř 100% rozdíl v rychlosti projeví. Není také nadále nutné spouštět generování sitemap CRONem v danou hodinu – sitemapa bude prostě po 24 hodinách přegenerována sama stínovým serverem. Stejně tak je to se všemi javascripty a css, kde se komprese ukazuje ještě efektivnější.
Ještě odkážu na web, který teď občas používám k testování efektivnosti komprese. Služba srovnává poměr komprese a zaslané hlavičky, což lze dobře uplatnit při ladění. Pěkné.