Wraz z rozwojem naszej strony internetowej, zaczniemy zauważać znaczące spadki w płynności działania. Jedną z głównych przyczyn początkujących programistów jest złe gospodarowanie zasobami serwera. Wiele osób boi się korzystać z pamięci cache i jest to dość poważny błąd.
1. Przeznaczenie skryptu
Załóżmy, że tworzymy stronę pod obsługę gry stworzonej na Unity. Napisaliśmy stronę, ostylowaliśmy ją i umieściliśmy na niej grę, którą dostarczył nam inny programista. Po pewnym czasie wpadacie na pomysł tablicy wyników przechowywanej w bazie danych. Programista od gry wyciąga dane o punktach i dostarcza je Tobie. Ty zaś przetwarzasz te dane i zapisujesz je w bazie danych. Dodatkowo na stronie umieszczasz tablicę pobierającą te dane z bazy. Co się stanie?
W najlepszym przypadku strona pod obciążeniem przestanie się ładować kolejnym użytkownikom. Dzieje się tak ponieważ każdy nowy użytkownik wchodzący na stronę uruchamia skrypt pobierający dane z bazy co obciąża serwer. Na szczęście można temu zaradzić w banalny sposób.
Wykorzystamy do tego kolejne dwa skrypty w dwóch osobnych plikach. Potrzebne one będą do zapisania wyniku wcześniej wspomnianego wyniku skryptu. A dokładniej?
- Po uruchomieniu strony wchodzi na nią pierwszy użytkownik
- Podstawowy skrypt zawarty w pliku .php wykonuje się normalnie, a nasze dwa kolejne skrypty zapamiętują jego wynik w pliku .html
- Kolejny użytkownik użytkownik wchodząc teraz na stronę nie będzie już ładował kolejny raz tego samego skryptu, tylko dużo szybciej pobierze sobie nasz nowy plik .html
- Po ustalonym przez nas czasie nasz plik .html umrze i zostanie wygenerowany kolejny raz – ma to na celu odświeżenie danych
2. Wady i zalety
Takie rozwiązanie mimo, iż przyśpieszy ładowanie się strony wielu użytkownikom. Posiada ono kilka istotnych wad. Należy pamiętać, że po każdym procesie zapisania wyniku pliku .php jako plik .html, dane pobierane np. z bazy danych nie będą odświeżane na bieżąco dla każdego użytkownika. Przez cały okres istnienia jednego pliku .html wyniki w przykładowej tablicy wyników gry, będą z momentu generowania tego pliku, aż do kolejnego generowania.
Nie można też wykorzystywać tego przy każdym pliku. Trzeba się samemu zorientować czy w przypadku naszej strony coś nie potrzebuje być odświeżane na bieżąco dla każdego unikalnego użytkownika.
Wydaje się to jednak mało istotna wada jeżeli możemy przy np. 200 jednoczesnych użytkownikach ograniczyć odwołania do bazy danych z 200 do 1.
3. Implementacja
Do zaimplementowania tej metody będziemy potrzebowali min. 3 plików .php:
- Plik ze skryptem umieszczanym na górze pliku docelowego – to on będzie odpowiadał za sprawdzanie czy istnieje już wygenerowany plik .html i czy nie jest już za stary.
- Plik ze skryptem umieszczanym na dole pliku docelowego – to on będzie odpowiadał za zakończenie generowania pliku .html, zapisanie go do pamięci cache oraz wysłania informacji do przeglądarki.
- Plik docelowy – dowolna strona zawierająca skrypt PHP, którego działanie chcemy zoptymalizować.
3a. Top-cache.php
<?php$url = $_SERVER[“SCRIPT_NAME”];$break = Explode(‘/’, $url);$file = $break[count($break) – 1];$cachefile = ‘cached-‘.substr_replace($file ,””,-4).’.html’;$cachetime = 600; // Tutaj ustawiamy czas życia cache’a w sekundach – aktualnie jest to 10min// Serve from the cache if it is younger than $cachetimeif (file_exists($cachefile) && time() – $cachetime < filemtime($cachefile)) {echo “<!– Cached copy, generated “.date(‘H:i’, filemtime($cachefile)).” –>\n”;readfile($cachefile);exit;}ob_start();?>
3b. Bottom-cache.php
<?php$cached = fopen($cachefile, ‘w’);fwrite($cached, ob_get_contents());fclose($cached);ob_end_flush();?>
3c. Index.php
<?phpinclude(‘php/top-cache.php’);$db = mysqli_connect(…);$get_scores = ‘SELECT * FROM score_board ORDER BY Wynik DESC LIMIT 10’;$scores = mysqli_query($db, $get_scores);?><!DOCTYPE html><html lang=”pl-PL”><head><meta charset=”utf-8″><link rel=”icon” type=”image/png” href=”TemplateData/favicon.png” /></head><body><div class=”webgl-content”><div class=”footer”><a href=”#score-board” data-toggle=”modal” data-target=”#score-board”><div class=”btn2″>TOP 10</div></a></div></div><div class=”modal” id=”score-board” tabindex=”-1″ role=”dialog”><div class=”modal-dialog” role=”document”><div class=”modal-content”><div class=”modal-header”><h5 class=”modal-title”>Modal title</h5><button type=”button” class=”close” data-dismiss=”modal” aria-label=”Close”><span aria-hidden=”true”>×</span></button></div><div class=”modal-body”><div class=”score-table”><h3>SCOREBOARD<br><span><small>(wyniki są odświeżane co 10min)</small></span></h3><table><tr><th>Nazwa</th><th>Wynik</th></tr><?phpforeach($scores as $user) {echo ‘<tr><td>’.$user[‘Nazwa’].'</td><td>’.$user[‘Wynik’].’ pkt.</td></tr>’;}?></table></div></div><div class=”modal-footer”><button type=”button” class=”btn btn-close” data-dismiss=”modal”>ZAMKNIJ</button></div></div></div></div></body></html><?phpinclude(‘php/bottom-cache.php’);?>
Za pomocą funkcji include() na początku pliku index.html (lub dowolnego pliku jaki chcemy zoptymalizować) dołączamy plik top-chache.php. Sprawdzi on czy jest już wygenerowany plik wynikowy i czy nie jest on zbyt stary do pokazania użytkownikowi. W przypadku gdy taki plik nie istnieje lub jest za stary, serwer wygeneruje go dla pierwszego użytkownika jaki wejdzie na stronę (będzie to trwało trochę dłużej niż kolejne ładowania strony, ponieważ muszą wykonać się skrypty php zawarte w nim) i zapisze na serwerze. Każda kolejna osoba jaka wejdzie na stronę zobaczy wygenerowany plik. Ważne jest, żeby korzystać z tego rozwiązania rozsądnie i nie zapisywać w ten sposób danych, które powinny być różne dla każdego użytkownika.