05/2007
Technika
50
CakePHP
www.phpsolmag.org
51
W
ielokrotne generowanie stron,
których zawartość nie zmienia
się, powoduje zbędne obciążenie
serwera WWW i bazy danych. Każde żąda-
nie od użytkownika musi zostać przetworzo-
ne, a wynik skierowany do przeglądarki in-
ternetowej, jednak za każdym razem serwer
pobiera te same dane. Nie stanowi to proble-
mu, gdy strony przegląda kilku użytkowni-
ków, ale kłopoty mogą się pojawić wraz ze
wzrostem popularności serwisu. Im więcej
użytkowników, tym bardziej serwer będzie
obciążony wykonywaniem zadań, które pro-
wadzą do wyświetlenia stron nieróżniących
się od siebie wcale lub różniących się tylko
w niewielkim stopniu. Naturalnym rozwią-
zaniem problemu spadku wydajności jest
zapisywanie „na boku” generowanych stron
i udostępnianie ich innym użytkownikom.
Zamiast za każdym razem generować tą samą
zawartość strony wystarczy przy pierwszym
wyświetleniu zapamiętać ją i używać przy
kolejnych wywołaniach. Technika ta nazywa
się page caching (pol. buforowanie stron) i jest
najprostszą metodą przyspieszania działania
serwisu. Przy pierwszym wyświetleniu stro-
na zostaje zapisana do pliku HTML. Każde
następne odwołanie do tej samej strony po-
woduje, iż do przeglądarki użytkownika zo-
stanie wysłana zawartość bezpośrednio z ca-
che z pominięciem wszystkich etapów, dzię-
ki którym strona została pierwotnie wygene-
rowana. W praktyce odbywa się to prawie
tak szybko jak udostępnianie statycznych
stron HTML.
Cache przeglądarki internetowej
Zamiast za każdym razem generować tę sa-
mą zawartość strony wystarczy przy pierw-
szym wyświetleniu zapamiętać ją i używać
przy kolejnych wywołaniach – Rysunek 1.
Właściwie w każdej nowoczesnej przeglą-
darce internetowej znajdują się ustawienia
związane z cache. Najczęściej jest to para-
metr określający miejsce zarezerwowane
na pliki tymczasowe przeglądanych stron
WWW. Zasady aktualizacji cache są proste.
Przeglądarka za pomocą znaczników HTTP
sprawdza, czy przechowywane dane są aktu-
alne – Listing 1. i w miarę możliwości korzy-
sta z nich zamiast pobierać dane z Internetu.
Dzięki temu powrót do poprzednio wyświe-
tlanej strony WWW w przeglądarce (przy-
cisk „wstecz”) powoduje szybkie wyświetle-
nie informacji, najczęściej bez konieczności
pobierania danych z sieci.
Kontrola aktualności cache odbywa się
za pomocą znaczników:
Cache - Control,
Expires, Last-Modified
oraz
ETag
przesyła-
nych w nagłówku stron WWW:
Expires: DATA_GMT
– Znacznik określa ter-
min możliwej zmiany lub wygaśnięcia ważno-
ści dokumentu. Po upływie określonego cza-
su (liczonego względem GMT) dokument mo-
że ulec zmianie lub zostać usunięty. Najprost-
szym sposobem wymuszenia, by plik nie zo-
stał umieszczony w cache, jest przypisanie da-
ty, która minęła. Znacznik idealnie nadaje się
do określania polityki tworzenia cache plików
graficznych, które bardzo rzadko ulegają zmia-
nie – Listing 1.
Cache-Control
: DYREKTYWA – Znacznik
określa sposób zachowania mechanizmu bu-
forowania plików (zarówno serwera WWW,
jak i serwerów proxy) mówiącego, co powin-
no być buforowane i co może być przechowy-
wane w cache. Najbardziej przydatne są poniż-
sze dyrektywy:
• max-age=[sekundy] – określa maksy-
malny czas, w którym dane są traktowa-
ne jako aktualne (liczony względem da-
ty określonej przez znacznik Last-Modi-
fied);
• public – wymusza buforowane (przy-
datne dla stron, które w normalnych
warunkach nie są umieszczane w ca-
che);
CakePHP
Cache jest mechanizmem umożliwiającym zredukowanie opóźnienia w
dostarczaniu danych do użytkownika oraz zmniejszenia obciążenia serwera.
W aplikacjach internetowych często zachodzi konieczność wyświetlania tych
samych informacji wielokrotnie. Np. sklep internetowy wyświetla listę dostępnych
produktów w odpowiedzi. na każde żądanie potencjalnych klientów.
Dowiesz się...
• Poznasz różne techniki buforowania stron
WWW oraz możliwość ich praktycznego zasto-
sowania w CakePHP.
Powinieneś wiedzieć...
• Wymagana jest znajomość framework Cake-
PHP. Przydatna będzie znajomość języka SQL
i umiejętność administrowania bazą danych
MySQL.
Poziom trudności
Buforowanie stron
Listing 1. Przykładowe żądanie i odpowiedź
serwera WWW
HEAD / HTTP/1.1
HOST: localhost
HTTP/1.1 200 OK
Date: Mon, 02 Jul 2007 21:24:12 GMT
Server: Apache
Accept-Ranges: bytes
X-Powered-By: PHP/4.2.2
Set-Cookie: PHPSESSID=
ac35d9b842215f4fb23ca419337af4b8;
path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache,
must-revalidate
Pragma: no-cache
Connection: close
Content-Type: text/html
Content-Language: pl
05/2007
Technika
50
CakePHP
www.phpsolmag.org
51
• no-cache – wymusza pominięcie cache
(przeglądarki i serwerów proxy) i pobiera-
nie danych bezpośrednio z Internetu;
• no-store – wymusza usunięcie danych z
cache zaraz po przesłaniu ich do użytkow-
nika;
• must-revalidate – wymusza sprawdzanie
stanu przedawnionych dokumentów znaj-
dujących się w cache.
Last-Modified: DATA _ GMT
– Znacznik okre-
śla datę ostatniej modyfikacji dokumentu –
Listing 1.
ETag
: ZNACZNIK – Znacznik jest
unikalnym identyfikatorem strony genero-
wanym przez serwer WWW, który zmie-
nia się za każdym razem, gdy przesyłane da-
ne ulegną modyfikacji. Znaczniki możemy
wysyłać do przeglądarki za pomocą funkcji
header()
– Listing 2.
Page cache
Mechanizm page cache jest powiązany z adre-
sem URL. To na jego podstawie w kontrolerze
zapada decyzja, czy strona ma być wygenero-
wana dynamicznie, czy też ma być użyty ca-
che. Jeżeli użytkownik już wcześniej odwoły-
wał się do określonego adresu WWW, to zo-
stał wygenerowany plik cache – o ile prezen-
towane informacje nie uległy zmianie, to po-
nowne odwołanie do tego samego adresu spo-
woduje udostępnienie danych wcześniej wy-
generowanych. Z tego faktu wynikają pewne
ograniczenia. Strony zależące od parametrów
przekazywanych w URL lub od informacji
przechowywanych w sesji nie będą mogły
skorzystać z page cache, podobnie jak strony,
których zawartość jest uzależniona od czasu.
Adres WWW takich witryn może być za każ-
dym razem inny i w ten sposób ciągle byłyby
tworzone kolejne pliki cache. Sposób działa-
nia page cache (buforowanie całej strony) do-
skonale sprawdza się w przypadku stron, któ-
rych zawartość nie zmienia się często. Jest to
trudne do osiągnięcia, jeżeli prezentowanych
jest wiele danych z różnych źródeł. Jeżeli zaj-
dą zmiany w dowolnym źródle danych, plik
cache będzie musiał zostać ponownie wyge-
nerowany, co przy częstych zmianach sta-
wia pod znakiem zapytania sens używania
tej technologii. W praktyce jednak strony
WWW można podzielić na fragmenty, które
są statyczne, oraz na takie, które zmieniają się
często, i poddać buforowaniu tylko te ostat-
nie. Wynikowa strona jest wtedy „składana”
z mniejszych bloków, z których część będzie
znajdowała się w cache. Jest to bardzo intu-
icyjne – w przypadku sklepu internetowego
lista produktów jest fragmentem, który naj-
rzadziej ulega zmianom, a z kolei koszyk za-
kupów klienta może zmieniać się dynamicz-
nie. Wykorzystanie page cache w CakePHP
zaczniemy od zapoznania się konfiguracją
serwera. Domyślnie cache widoków jest za-
blokowane. By je aktywować, musimy zmie-
nić na
TRUE
wartość stałej
CACHE_CHECK
w
pliku /app/config/core.php.
define ('CACHE_
CHECK', true)
; W kontrolerze powiązanym
z widokiem, dla którego włączamy cache, mu-
simy dodać CacheHelper przez umieszczenie
kodu:
var $helpers = array('Cache')
;
Następnie należy określić, co chcemy umie-
ścić w cache. Do zmiennej $cacheAction mu-
simy przypisać tablicę zawierającą akcje, któ-
re mają być buforowane, oraz czas (w sekun-
dach), przez który cache ma być aktualny
(można używać liczb lub zapisów „1 day” czy
„60 seconds”) – Listing 3.
W praktyce zdarza się, że pewne fragmen-
ty strony są wypełniane dynamicznymi dany-
mi i nie mogą znaleźć się w cache ze względu
na wyświetlane dane. Wystarczy wówczas, że
Rysunek 1. Przesyłanie do użytkowników stron WWW
�����������������������������������
�����������
����������
�����������������������������������������
����������������������������������
�����������
����������
�����
Listing 2. Przykładowe znaczniki wysyłane do przeglądarki za pomocą funkcji header()
// strona nie będzie umieszczona w cache przeglądarki
// wymaga obsługi protokołu HTTP/1.1
header
(
"Cache-Control: no-cache, must-revalidate"
)
;
// data z przeszłości
header
(
"Expires: Mon, 26 Jul 1997 05:00:00 GMT"
)
;
Lisgin 3. Definiowanie akcji, które mają zostać buforowane przez CakePHP
// Możemy zdefiniować cache dla wszystkich parametrów akcji
var
$cacheAction
=
array
(
'view/'
=
>
86400
)
;
// lub dla każdego parametru oddzielnie.
var
$cacheAction
=
array
(
'view/23/'
=
>
21600
,
'view/48/'
=
>
21600
)
;
QUERY-CACHE
Nowoczesne bazy danych są najczęściej wy-
posażone w mechanizm QUERY-CACHE po-
wodujący zapamiętanie zapytań kierowa-
nych do bazy oraz skojarzonych z nimi wyni-
ków. Takie samo zapytanie SQL do bazy da-
nych spowoduje przekazanie wyników prze-
chowanych w QUERY-CACHE bez koniecz-
ności odczytu informacji z plików bazoda-
nowych. Cache jest czyszczony w przypad-
ku zmian w tabelach do których zapytania
się odwołują. MySQL4 posiada błąd, któ-
ry powoduje czyszczenie całego QUERY-CA-
CHE w przypadku zmian w dowolnej tablicy,
co niekorzystnie wpływa na czas odpowiedzi
serwera na te same zapytania.
05/2007
Technika
52
CakePHP
www.phpsolmag.org
53
fragment kodu, który nie powinien być bu-
forowany, określimy za pomocą znaczników
<cake:nocache>
oraz
</cake:nocache>
– Li-
sting 4.
Czyszczenie cache
Przy korzystaniu z cache kluczowym momen-
tem w funkcjonowaniu serwisu jest sposób
reakcji na zmiany w prezentowanych danych.
Jeżeli nie będzie sprawnego mechanizmu in-
formowania aplikacji, które pliki cache nale-
ży usunąć, to użytkownikowi zostaną zapre-
zentowane błędne nieaktualne dane. W naj-
prostszym przypadku w reakcji na zmiany
możemy usunąć wszystkie pliki cache. Roz-
wiązanie to ma jednak tę wadę, że nawet nie-
wielka zmiana spowoduje konieczność czaso-
chłonnego generowania cache na nowo. Zde-
cydowanie lepiej jest usuwać tylko te pliki ca-
che, które prezentują dane, które uległy zmia-
nie. CakePHP wykorzystuje fakt, że prezen-
towane na stronach WWW dane są powią-
zane z modelem danych, a cache jest związa-
ny z widokiem (który z kolei może wyświe-
tlać dane z różnych modeli danych). Zmia-
na danych dowolnego modelu spowoduje
więc automatyczne usunięcie cache dla całe-
go widoku. CakePHP automatycznie usuwa
cache, gdy nastąpi zmiana w stanie aplikacji.
Jeżeli użytkownik spowoduje działanie, któ-
re będzie skutkowało zmianami w bazie da-
nych (INSERT, UPDATE, DELETE), zosta-
nie usunięte cache dla widoku powiązane-
go z kontrolerem odwołującym się do mode-
li danych, które uległy zmianie. Istnieje moż-
liwość ręcznego sterowania cache i usuwania
nieaktualnych danych za pomocą funkcji cle-
arCache(). Jako parametr przekazujemy na-
zwę kontrolera, kontrolera i akcji lub kontro-
lera, akcji i parametrów identyfikujących plik
cache – Listing 5.
W prosty sposób można zaimplemento-
wać dodatkowy scenariusz czyszczenia cache
sprawdzający się w sytuacjach, gdy nie może-
my zapobiec cyklicznemu tworzeniu się no-
wych plików cache, ale jednocześnie chcemy
uniknąć ciągłego usuwania plików. Zamiast
spowalniać działanie aplikacji ciągłym testo-
waniem aktualności cache możemy urucho-
mić dodatkowy proces działający w tle. Pro-
ces ten będzie odpowiedzialny za cykliczne
czyszczenie cache co określony (konfiguro-
walny) przedział czasowy niezależnie od ob-
ciążenia aplikacji.
Składowanie danych
Najprostszym sposobem przechowywania
cache są pliki umieszczone bezpośrednio w
systemie operacyjnym (jest to jedyny sposób
przechowywania cache obsługiwany automa-
tycznie przez CakePHP w wersji 1.1.xx). Wy-
generowana strona HTML zostanie umiesz-
czona w publicznie dostępnym obszarze ser-
wera (w miejscu określonym ścieżką dostępu
wskazywaną przez stałą
$CACHE
) – każde od-
wołanie do tej samej strony będzie wówczas
przekierowywane na plik cache. Rozwiąza-
nie takie oprócz oczywistych zalet, takich jak
prostota implementacji czy dobra wydajność,
ma podstawową wadę: nie jest rozwiązaniem
skalowalnym. Jeżeli nasz serwis będzie się
rozwijał i zajdzie konieczność uruchomie-
nia dodatkowego serwera WWW, to stanie-
my przed problemem związanym z dystry-
bucją plików cache i ich synchronizacją. Za-
pytania od użytkowników mogą być kierowa-
ne do dowolnego serwera, każdy będzie więc
z nich tworzył pliki cache niezależnie. Poza
tym usunięcie cache z jednego serwera nie
spowoduje usunięcia plików z pozostałych
serwerów. Można co prawda utworzyć jeden
wspólny sieciowy filesystem na potrzeby ca-
che wszystkich serwerów, ale rozwiązanie
traci wtedy swoją prostotę. Innym rozwiąza-
niem jest umieszczanie danych cache w bazie
danych. Jest to elastyczniejsze od plików ca-
che w systemie operacyjnym – głównie kosz-
tem dodatkowego obciążenia zasobów serwe-
Memcached
System cache przechowujący dane w pamięci RAM, umożliwiający zapisywanie danych i obiek-
tów. Wysoce wydajny i skalowalny umożliwia łączenie serwerów działających w oparciu o różne
architektury systemowe. Stosowany m.in. w serwisach LiveJournal i Wikipedia. System memca-
ched jest dostępny w repozytoriach wielu dystrybucji Linuksa (kod źródłowy można pobrać z ad-
resu http://www.danga.com/memcached). Obsługę memcached w PHP zapewnia binarne rozsze-
rzenie, dostępne na pecl.php.net.
Krótki przegląd metod API:
• Memcache::add – dodaje element do serwera.
• Memcache::addServer – dDodaje serwer memcached do listy wykorzystywanych serwerów.
• Memcache::close – zamyka połączenie.
• Memcache::decrement – zmniejsza wartość elementu.
• Memcache::delete – usuwa element z serwera.
• Memcache::flush – usuwa wszystkie elementy z serwera.
• Memcache::get – zwraca element z serwera.
• Memcache::getExtendedStats – statystyki wszystkich serwerów memcached.
• Memcache::getServerStatus – zwraca stan serwerów memcached.
• Memcache::getStats – statystyki serwerów.
• Memcache::getVersion – zwraca wersję serwera memcached.
• Memcache::increment – inkrementuje wartość elementu.
• Memcache::pconnect – otwiera stałe połączenie.
• Memcache::replace – zmienia wartość podanego elementu.
• Memcache::set – zapisuje dane na serwerze.
• Memcache::setCompressThreshold – włącza automatyczną kompresję dużych wartości.
• Memcache::setServerParams – zmienia parametry i stan serwera.
Listing 4. Przykład wyłączenia buforowania fragmentu kodu widoku
<
h1
>
Ostatnie 10 wiadomości!
<
/h1
>
<
cake:nocache
>
<
ul
>
<?
php
foreach
(
$recentMessages
as
$message
)
:
?>
<
li
>
$message
[
'title'
]<
/li
>
<?
endforeach;
?>
<
/ul
>
<
/cake:nocache
>
Listing 5. Funkcja clearCache() usuwająca nieaktualne pliki cache
// Usuń wszystkie strony z cache, bazując na nazwie kontrolera
clearCache
(
'controller'
)
;
// Usuń wszystkie strony z cache, bazując na nazwie kontrolera i nazwie akcji
clearCache
(
'controller_action/'
)
;
// Usuń wszystkie strony z cache, bazując na nazwie kontrolera, nazwie akcji
// i parametrze
// Do funkcji clearCache() można przekazywać wiele parametrów
clearCache
(
array
(
'controller_action_params'
,'controller2_action_params
))
;
05/2007
Technika
52
CakePHP
www.phpsolmag.org
53
Listing 6. Struktury danych wykorzystane do przechowywania cache
mysql
>
desc dbcache;
mysql
>
desc dbcache;
+------------+------------------+------+-----+---------+------
----------+
| Field | Type | Null | Key |
Default
|
Extra |
+------------+------------------+------+-----+---------+------
----------+
| key |
int
(
10
)
unsigned | NO | PRI | NULL |
|
| value | text | YES | | NULL |
|
| expires_at | datetime | YES | | NULL |
|
+------------+------------------+------+-----+---------+------
----------+
// przykładowy model danych obsługujący buforowanie stron
// w bazie danych klasa Cache
class
MyCache
extends
AppModel
// jeżeli używamy PHP4, musimy zdefiniować zmienną
// zawierającą nazwę klasy
var
$name
=
'MyCache'
;
// korzystamy z bazy danych – tabeli o nazwie cache
var
$useTable
= ‘cache’;
// metoda wyszukująca wartość skojarzoną z kluczem
// i zwracająca dane jako zmienną PHP
function find(
$key
)
{
$rc
=
$this
-
>
query
(
"select * from cache where key =
'$key'
and
expires_at
<
NOW
()
limit 1"
)
;
return
unserialize
(
$rc
[
'cache'
][
0
][
'value'
])
;
}
// metoda przechowująca w bazie danych klucz razem
// z wartością
function
store(
$key
,
$value
,
$expires
=null
)
{
// jutro
if
(
is_null
(
$expires
))
$expires
=
time
()
+
(
24 * 60 * 60
))
;
$expires
=
date
(
'Y-m-d H:i:s'
,
$expires
)
;
$value
= serialize
(
$value
)
;
return
$this
-
>
query
(
"replace cache set value =
'$value'
,
$expires_at
=
'$expires'
where key =
'$key'
)
;
}
// metoda usuwająca przechowywane dane na podstawie klucza
// wyszukiwania
function
delete(
$key
)
{
return
$this
-
>
query
(
"delete * from cache where key =
'$key'
"
)
;
}
// metoda usuwająca z bazy danych wszystkie dane,
// których termin ważności minął
function
purge(
)
{
return
$this
-
>
query
(
"delete * from cache where
expires_at < NOW()"
)
;
}
}
// przykładowy kontroler wykorzystujących cache
// klasa MessagesControler wyświetlająca wiadomości
// internetowego forum
class
MessagesController
extends
AppController
{
var
$name
=
'Messages'
;
var
$helpers
=
array
(
'Html'
,
'Time'
)
;
var
$layout
=
'default'
;
var
$uses
=
array
(
'Forum'
,
'Topic'
,
'Comment'
,
'Message'
,
'MyCache'
)
;
function
view(
$id
)
{
// pobierz informacje o temacie dyskusji i powiązaną
// z nim listę komentarzy jeżeli temat nie istnieje,
// ponownie wyświetl listę działów
$topic
=
$this
-
>
MyCache-
>
find
(
'topic'
.
$id
)
;
if
(
empty
(
$topic
))
{
$topic
=
$this
-
>
Topic-
>
find
(
array
(
'Topic.id'
=
>
$id
,
'Topic.topic_id'
=
>
0
))
;
if
(
!
empty
(
$topic
))
{
// przechowuj przez tydzień
$this
-
>
MyCache-
>
store
(
'topic'
.
$id
,
$topic
,
time
()
+
(
7 * 24 * 60 * 60
))
;
}
else
{
$this
-
>
redirect
(
'/forums/index'
)
;
exit
()
;
}
}
// przekaż zmienną $topic do widoku
$this
-
>
set
(
'topic'
,
$topic
)
;
}
function
remove(
$id
)
{
// usuń temat dyskusji wraz ze wszystkimi wiadomościami
// usuń zbędne pliki z cache
if
(
$this
-
>
Topic-
>
drop
(
$id
, true
))
$this
-
>
MyCache-
>
delete
(
'topic'
.
$id
)
;
$this
-
>
redirect
(
'/forums/index'
)
;
exit
()
;
}
05/2007
Technika
54
ra mechanizmami zapisu i odczytu danych
(zobacz ramka QUERY-CACHE). Oczywi-
ście istnieje możliwość skalowania takiego
rozwiązania, jednak nie jest ono proste po-
nieważ wymaga żmudnej konfiguracji (repli-
kacja baz danych) i nie jest standardowo ob-
sługiwane przez CakePHP 1.1.xx. Przykłado-
wy model danych obsługujący przechowywa-
nie cache w bazie danych został przedstawio-
ny w Listingu 6.
Najbardziej elastycznym sposobem prze-
chowywania danych jest mechanizm mem-
cached przechowujący dane w pamięci RAM
serwera (zobacz ramka). W miarę, jak dane
będą zapełniały przydzieloną pamięć, system
będzie automatycznie usuwał te, które były
najrzadziej używane (można też usuwać da-
ne za pomocą odpowiednich wywołań syste-
mowych).
Memcached został także wyposażony w
mechanizmy równoważące obciążenie, gdy
wykorzystywanych jest kilka serwerów, któ-
re można w prosty sposób przyłączać (lub
odłączać) bez konieczności przerywania dzia-
łania serwisu (obsługa memcached zostanie
włączona do CakePHP począwszy od wer-
sji 1.2.xx).
Typowa sesja połączenia z memcached z po-
ziomu PHP została przedstawiona na Listin-
gu 7. W pierwszej kolejności następuje zdefi-
niowanie puli dostępnych serwerów pracują-
cych pod kontrolą memcached. Każdy z nich
będzie wykorzystywany proporcjonalnie do
wagi określonej podczas inicjalizacji połącze-
nia i w razie awarii zastąpiony przez kolejny
serwer z listy.
Każdy dostęp do danych poprzedzony jest
testem, czy informacje są dostępne w cache.
Tylko w przypadku negatywnym nastąpi ko-
nieczność wykonania czasochłonnych obli-
czeń, po których wynik zostanie zapisany w
cache (kolejne zapytania będą więc korzysta-
ły z bufora). Memcached sam zatroszczy się o
usunięcie zbędnych (przestarzałych) danych
z pamięci – w naszym przykładzie po 10 se-
kundach.
Memcached ma jeszcze jedną zaletę – moż-
na go użyć jako mechanizm przechowują-
cy dane nie tylko na potrzeby buforowania
całych stron (page cache). Możemy w cache
umieszczać dowolne dane (wyniki obliczeń,
dynamicznie zmieniające się relacje między
danymi) i na ich podstawie generować stro-
ny WWW.
Podobnie jak w przypadku page cache pro-
blemem jest określenie, czy strony na których
były prezentowane dane, które uległy mo-
dyfikacji, znajdują się w cache. Memcached
umożliwia przechowywanie wyników obli-
czeń, więc nie możemy polegać na prostej za-
leżności mówiącej, że w przypadku zmian w
modelu danych należy usunąć cache związa-
ny z widokiem prezentującym dane.Zamiast
tego można posłużyć się sztuczką polegają-
cą na powiązaniu przechowywanych danych
przechowywanych w cache ze znacznikiem
sygnalizującym zmiany. Wystarczy, że utwo-
rzymy model danych, który będzie dostarczał
informacje o stanie aplikacji, np. unikalny nu-
mer, niezmienny tak długo, jak długo nie na-
stąpiły zmiany w bazie danych lub innych ob-
liczeniach.
Jeżeli tym numerem będziemy posługiwa-
li się przy obsłudze cache, to jego zmiana wy-
musi ponowne przeliczenie zmienionych da-
nych. Jeżeli przestrzeń przeznaczona na bu-
for będzie się zmniejszać, memcached auto-
matycznie usunie dane, które przez określo-
ny czas nie były aktywne.
Rozwiązanie takie sprawdzi się przede
wszystkim przy skomplikowanych stronach
WWW opartych o przechowywane w cache
dane pochodzące z czasochłonnych obliczeń.
Koszt zaangażowania zasobów serwera w wy-
krycie zmian w stanie aplikacji będzie wów-
czas zrównoważony przez oszczędności wy-
nikające z braku potrzeby wykonywania cza-
sochłonnej generacji strony.
Podsumowanie
Mechanizm page cache w CakePHP w połą-
czeniu z umiejętnym wykorzystaniem cache
przeglądarki internetowej może zredukować
opóźnienia w dostarczaniu danych do użyt-
kownika oraz zmniejszyć obciążenie serwera
WWW i bazy danych. Warto zwrócić szcze-
gólną uwagę na technologię memcached, któ-
ra zapewnia szybki dostęp do danych zawar-
tych w cache, jest elastyczna i skalowalna,
dzięki czemu może „rosnąć” razem z naszym
serwisem.
PIOTR GAPIŃSKI
Autor w wolnych chwilach zajmuje się programo-
waniem w różnych językach (głównie Rebol, Ruby,
PHP i AmigaE).
Kontakt z autorem: narg@polbox.com
Listing 7. Wykorzystanie memcached z poziomu PHP
// utworzenie puli dostępnych serwerów memcached
// każdy z nich będzie wykorzystywany proporcjonalnie
// do listy wag przekazanych jako prametr do metody Mamcache::addServer()
$memcache
=
new
Memcache;
$memcache
-
>
addServer
(
'memcache_host1'
,
11211
,
50
)
;
$memcache
-
>
addServer
(
'memcache_host2'
,
11211
,
25
)
;
$memcache
-
>
addServer
(
'memcache_host3'
,
11211
,
25
)
;
$memcache
=
new
Memcache;
$memcache
-
>
connect
(
'localhost'
,
11211
)
or
die
(
'Nie mogę się połączyć'
)
;
if
(
$get_result
=
$memcache
-
>
get
(
'key'
))
{
// jeżeli obiekt jest w cache, to skorzystaj z niego
echo
'
<
b
>
Dane z serwera
<
/b
>
:
<
br/
>
';
echo
$get_result
->
str_attr
.
'
<
br
/
>
'
;
echo
$get_result
-
>
int_attr;
}
else
{
// w cache nie ma żądanych danych, zapisz dane
$tmp_object
=
new
stdClass;
$tmp_object
-
>
str_attr =
'test'
;
$tmp_object
-
>
int_attr =
time
()
;
$memcache
-
>
set
(
'key'
,
$tmp_object
, false, 10
)
or
die
(
'Nie udało się zapisać elementu'
)
;
echo
'Zapisane dane zostaną usunięte po 10 sekundach
<
br/
>
'
;
echo
'Odśwież stronę, by zobaczyć dane zapisane na serwerze memcached'
;
}