PHP i Memcached
14 July 2008
Comments
Memcached to system keszowania oparty o pamięć RAM umożliwiający zapisywanie danych i obiektów. Stworzony został dla serwisu LiveJournal, lecz obecnie stosowany jest na wielu serwisach jak digg czy slashdot. Zaleta: wysoce wydajny i skalowalny, możliwość łączenia serwerów memcached działających na różnych maszynach.Instalacja
Memcached dostępny jest w repozytoriach wielu dystrybucji Linuksa, a jeżeli go brak to kompilacja nie powinna przysporzyć problemów. Zależnością jest libevent. Obsługę memcached w PHP zapewnia binarne rozszerzenie, dostępne na pecl.php.net. Kompilacja standardowa:phpize ./configure make make install
extension=memcached.so
Memcached w PHP
Oto krótki przegląd metod API (manual):- Memcache::add - Dodaje element do serwera
- Memcache::addServer - Dodaje 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
By móc korzystać z memcached musimy uruchomić lokalnie serwer memcaced. Najprostsze rozwiązanie to wykonanie w konsoli polecenia memcached w konsoli przez nieuprzywilejowanego użytkownika (nie-roota). Memcached uruchomi się z domyślnymi ustawieniami i będzie nasłuchiwał na porcie 11211.
Wykorzystanie
Oto prosty przykład wykorzystania API memcached:<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ('Nie mogę się połączyć');
$version = $memcache->getVersion();
echo '<b>Wersja Serwera</b>: '.$version.'<br/>';
Teraz już coś bardziej przydatnego - zapisywanie i pobieranie obiektów z serwera memcached:
<?php
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ('Nie mogę się połączyć');
IF ($get_result = $memcache->get('key'))
{
// obiekty są w keszu
echo '<b>Dane z serwera</b>:<br/>';
echo $get_result->str_attr.'<br />';
echo $get_result->int_attr;
}
else
{
// obiektów nie ma w keszu
$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';
}
bool Memcache::set ( string klucz, mixed wartość [, int flaga [, int czas_ważności]] )
Gdzie klucz - klucz pod jaką zapisana będzie wartość. flaga - określa Tak/Nie czy używać kompresji danych, a czas_ważności określa w sekundach czas przetrzymywania elementu na serwerze. Powyższy kod za pierwszym wykonaniem wyświetli tekst informujący o zapisaniu danych, lecz odświeżanie strony z kodem przed upływem 10 sekund będzie pokazywało zapisane dane. Po upływie 10 sekund element zostanie usunięty z serwerem a ponowne wykonanie skryptu zapisze nowe dane.
A teraz keszowanie wyników zapytań w Wordpressie. W pliku wp-includes/wp-db.php znajdujemy metodę:
<?php
function get_results($query = null, $output = OBJECT) {
$this->func_call = "\$db->get_results("$query", $output)";
if ( $query )
$this->query($query);
// Send back array of objects. Each row is an object
if ( $output == OBJECT ) {
return $this->last_result;
} elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
if ( $this->last_result ) {
$i = 0;
foreach( $this->last_result as $row ) {
$new_array[$i] = (array) $row;
if ( $output == ARRAY_N ) {
$new_array[$i] = array_values($new_array[$i]);
}
$i++;
}
return $new_array;
} else {
return null;
}
}
}
<?php
function get_results($query = null, $output = OBJECT) {
global $memcache;
$klucz = sha1($query);
IF ($get_result = $memcache->get($klucz))
{
return $get_result;
}
else
{
$this->func_call = "\$db->get_results("$query", $output)";
if ( $query )
$this->query($query);
// Send back array of objects. Each row is an object
if ( $output == OBJECT ) {
$memcache->set($klucz, $this->last_result, false, 300) or die ('Nie udało się zapisać elementu');
return $this->last_result;
} elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
if ( $this->last_result ) {
$i = 0;
foreach( $this->last_result as $row ) {
$new_array[$i] = (array) $row;
if ( $output == ARRAY_N ) {
$new_array[$i] = array_values($new_array[$i]);
}
$i++;
}
$memcache->set($klucz, $new_array, false, 300) or die ('Nie udało się zapisać elementu');
return $new_array;
} else {
return null;
}
}
}
}
$memcache = new Memcache; $memcache->connect('localhost', 11211) or die ('Nie mogę się połączyć');
Co powinno być keszowane ?
- Wolne i zasobożerne zapytania
- Często wywoływane strony
Kiedy stosować keszowane ?
- Duża baza i dużo zapytań
- Duża strona i dużo żądań
Keszowanie żadań HTTP, stron www
Niektóre serwery, jak np. Nginx pozwalają na keszowanie całych żądań HTTP. Temat zastosowania memcached będzie jeszcze kontynuowany w odpowiednich Bibliotekach (CMS, Linux)
RkBlog
Comment article