background image

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

background image

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.

background image

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

))

background image

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

()

;

   

}

background image

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'

;

}