Takie pojęcia jak „Pamięć podręczna” lub „Cache” brzmią dość technicznie i poważnie. Ręczna implementacja takich mechanizmów optymalizacyjnych może się wydawać trudna do wykonania. Tym bardziej, że dla wielu systemów istnieją płatne wtyczki do realizacji takiej funkcjonalności.
Rozszerzenia cache dla systemów open-source potrafią kosztować nawet kilkaset złotych. A dostawcy hostingu przekrzykują się jakie wtyczki są najbardziej kompatybilne z ich systemami. To wszystko będzie Ci się wydawać zabawne, kiedy pokażę Ci na czym polega pamięć podręczna bazująca na systemie plików, która często jest wykorzystywana na stronach i w sklepach internetowych.
Oszczędność jest to umiejętność unikania zbędnych wydatków.
Seneka Młodszy
W tym artykule odczaruję to pojęcie i pokażę, że stworzenie własnego systemu cache bazującego na plikach (lub innej pamięci np. Redis lub Memcached) to jedna z najprostszych technik optymalizacyjnych jaką może stworzyć nawet bardzo początkujący programista.
Zalety korzystania z Cache po stronie serwera
Zaletą korzystania z pamięci podręcznej jest przede wszystkim radykalne skrócenie czasu TTFB i wszelkie korzyści z tym związane czyli:
- oszczędność zasobów CPU i RAM,
- niższy koszt hostingu,
- większa wydajność strony,
- poprawa user experience,
- poprawa pozycjonowania strony,
Zasada działania pamięci podręcznej po stronie serwera
Działanie Cache polega na zapisaniu w pamięci o stosunkowo krótkim czasie dostępu wyniku działania dość złożonych mechanizmów. Tym „złożonym mechanizmem” może byc CMS, który generuje stronę za pomocą wielu połączeń do bazy danych i przeróżnych funkcji które generują obliczenia, operacje tekstowe itp…
W zdrowym CMSie strony są generowane praktycznie w mgnieniu oka i nawet bez systemu Cache strona ze średnim ruchem może spokojnie funkcjonować. Problem zaczyna się wtedy kiedy ważymy dosłownie pojedyncze sekundy TTFB lub kiedy ruch jest duży i chcemy zmniejszyć obciążenie serwera.
Cache strony za pomocą PHP
Symulacją tony wtyczek, które zawierają setki instrukcji warunkowych i pięknego kodu OOP, który nie grzeszy wydajnością niech będzie już wykorzystywany przy temacie memoizacji PHP algorytm wyszukiwania liczb pierwszych.
Wygenerowane wyniki będą symulacją strony internetowej ze złożoną logiką. Napiszemy własny system cache, który spowoduje, że przy kolejnych wizytach serwer nie będzie musiał wykonywać kolejny raz tego samego wysiłku.
Za pomocą metody microtime, którą miałem okazję pokazać we wpisie na temat testowania hostingów, sprawdzimy czas wykonywania skryptu.
<?php $t_start = microtime(true); function pierwsze($n){ for($i=1;$i<=$n;$i++){ $l = 0; for($j=1;$j<=$i;$j++){ if($i % $j==0){ $l++; } } if($l==2){ echo $i.", "; } } } ?> <h1>Witamy na naszej stronie, oto pierwsze liczby pierwsze:</h1> <div style="width:100%; height:300px; overflow:auto;"> <?php pierwsze(20000); ?> </div> <?php $t_koniec = microtime(true); $t_calkowite = ($t_koniec - $t_start); echo "<h3>Czas: ".$t_calkowite."</h3>"; ?>
Jak widać, skrypt wykonuje się w ponad 8 sekund:

Właściwy kod strony rozpoczyna się po funkcji microtime() a kończy po wyświetleniu wyniku.
Zapisywanie treści do pamięci podręcznej
Otaczamy cały kod odpowiedzialny za wygenerowanie treści strony specjalną funkcją ob_start();
Po wyświetleniu wszystkich treści kończymy instrukcją:
$content = ob_get_contents();
W wyniku tego cały strumień jaki powinien trafić na przeglądarkę został przekierowany do zmiennej w postaci zwykłego tekstu. Teraz ten tekst możemy sobie zapisać w pliku:
file_put_contents("cache.html", $content);
Jak widać, skrypt wygenerował plik HTML, który możemy teraz sprytnie wykorzystać. Całą stronę otaczamy zwykłym wyrażeniem logicznym:
if(file_exists("cache.html")){ echo file_get_contents("cache.html"); } else{ /* Oryginalny skrypt */ }
Przy pierwszym uruchomieniu skryptu otrzymaliśmy bardzo podobny wynik a przy drugim? Sprawdźcie sami:

Jak widać skrypt wykonał się ok. 10 000 razy szybciej. Cache jako technika optymalizacyjna jest tym efektywniejszy im dostęp do „oryginalnych” danych się wydłuża. Czyli im wolniejsza strona tym cache jest bardziej opłacalny.
Inwalidacja / czyszczenie cache
Każdy system cache powinien mieć jakiś system inwalidacji, czyli sposób na odświeżenie zwartych w nim danych. Na stronach dynamicznych, na których dochodzi do ręcznych aktualizacji wystarczy uruchamiać prostą funkcję przy jakiejkolwiek aktualizacji, która może mieć wpływ na treść strony którą optymalizujemy:
unlink("cache.php");
Na stronach, które pobierają dane z zewnątrz przyda się cache z czasem wygasania, czyli w naszym przypadku mogłoby to być zrobione w ten sposób:
if(file_exists("cache.html")){ if (time()-filemtime("cache.html") < 3600) { echo file_get_contents("cache.html"); } else{ content(); } else{ content(); }
Funkcja filemtime zwraca czas ostatniej aktualizacji, jeżeli przekracza on podany czas wygasania, uruchamiamy oryginalny skrypt i aktualizujemy cache.
Co zapisywać a czego nie zapisywać do pamięci podręcznej?
Nie ma sensu tworzyć mechanizmu cache z bardzo krótkim czasem wygasania. Paradoksalnie, cache obciąży hosting bo dojdą nam dodatkowe operacje dyskowe, które odświeżają cache. Warto też zwrócić uwagę, że za każdym razem kiedy cache działa, lekko spowolni wyświetlanie się strony, która jest generowana w locie.
Z takiego cache, który zapisuje całą stronę, powinny być wykluczone strony dynamiczne i te, które zależą od bieżącej sesji. Np. panele klienta, konta użytkownika gdzie występuje logowane nie powinny być wspierane takimi prostymi mechanizmami. Musimy pilnować aby każdy widział swoje aktualne dane. W takich sytuacjach cache może przechowywać tylko fragmenty strony lub przechowywać wynik działania konkretnej funkcji, podobnie jak w przypadku memoizacji.
Redis i memcached
Nic nie stoi na przeszkodzie aby system Cache korzystał z pamięci Redis i memchached. W przypadku stron s dużym ruchem korzystanie z tych systemów może być opłacalne bo jak pamiętamy zapisują one dane do pamięci RAM i odciążają dysk serwera.
Podsumowanie
Prosty system cache bazujący na plikach statycznych to zadanie dla początkującego programisty. Warto znać ideę działania pamięci podręcznej stron internetowych jeżeli zabieramy się za optymalizacje lub integrację z zewnętrznymi systemami.
Odpowiedz lub skomentuj