php i memcached, zaawansowane przypadki użycia
DESCRIPTION
Autor: Mariusz Gil Memcached to podstawowy element architektury aplikacji webowych o znacznym wolumenie ruchu. Choć typowe wdrożenie tego silnika ogranicza się wykorzystania podstawowych funkcjonalności (np. set/get w obrębie jednej instancji memcached), to tematyka łączenia aplikacji PHP z memcached jest o wiele bardziej rozległa. Strategie cache'owania danych w memcached, komunikacja z klastrem jego instancji i metody zmniejszania obciążenia warstwy sieciowej, przeciwdziałanie dog-pile effect, slab klasy i chunki i ich wpływ na optymalizację wykorzystywanej pamięci operacyjnej, różnice i wynikające z nich możliwości pomiędzy modułami klienckimi w PHP, rozwiązania alternatywne dla memcached – to tylko część zagadnień jaki zostaną przedstawione w prezentacji.TRANSCRIPT
PHP I MEMCACHEDZAAWANSOWANE PRZYPADKI UŻYCIA
Mariusz [email protected]
PHPCon 2010 Poland, Góry Świętokrzyskie, maj 2010
środa, 26 maja 2010
CO TO JEST MEMCACHED?
•Memcached to wysoce wydajny i skalowalny system pamięci podręcznej, oparty wyłącznie o pamięć RAM
•Ogólnego przeznaczenia, choć głównie stosowany podczas optymalizacji i skalowaniu aplikacji internetowych
środa, 26 maja 2010
ODROBINA HISTORII
• Autorem memcached jest Danga Interactive
• Projekt powstał w 2003 roku na potrzeby serwisu LiveJournal
•Od tamtej chwili stanowi podstawowy element architektury nowoczesnych aplikacji, a opracowany protokół stał się standardem
środa, 26 maja 2010
IDEA DZIAŁANIA
cache 1GB cache 1GB
rozdzielne cache nakażdym serwerze
memcached 2GB
wspólny cache dla wszystkichserwerów, implementowany jako
rozproszona tablica hashująca
środa, 26 maja 2010
IDEA DZIAŁANIA
// Pobranie danych bez cache’owaniafunction get_foo(int userid) { result = db_select("SELECT * FROM users WHERE userid = ?", userid); return result;}
// Pobranie danych z cache’owanie,function get_foo(int userid) { /* Najpierw sprawdzamy, czy dane są w cache */ data = memcached_fetch("userrow:" + userid); if (!data) { /* Nie znaleziono: odpytujemy bazę danych */ data = db_select("SELECT * FROM users WHERE userid = ?", userid); /* Następnie umieszczamy w cache dla następnych odwołań */ memcached_add("userrow:" + userid, data); } return data;}
przykład pochodzi ze strony http://en.wikipedia.org/wiki/Memcached
środa, 26 maja 2010
PRZYKŁADOWE ZASTOSOWANIA
• Cache zapytań SQL
• Cache stron, widoków, partiali
• Handler sesyjny
• Storage dla locków i liczników
środa, 26 maja 2010
OGRANICZENIA MEMCACHED
• Klucze o długości 250 znaków
•Wartość o maksymalnym rozmiarze 1MB
• Brak trwałości danych - to tylko cache, nie storage
• Brak bezpiecznego dostępu do serwera
środa, 26 maja 2010
ROZPOCZYNANIE PRACY
• Instalacja oprogramowania
wget http://memcached.org/latesttar -zxvf memcached-1.x.x.tar.gzcd memcached-1.x.x./configuremake && make testsudo make install
• Uruchomienie
memcached -m 1024 -u root -l 127.0.0.1 -p 11211 -vv
środa, 26 maja 2010
PODSTAWY PROTOKOŁU
• Protokół memcached to zaledwie kilka podstawowych poleceń:
• Komendy składujące: SET, ADD, REPLACE, APPEND, PREPEND, CAS, INCR/DECR, DELETE, FLUSH_ALL
• Komendy pobierające: GET, GETS
• Komendy statystyk: STATS, STATS ITEMS, STATS SLABS, STATS SIZES
środa, 26 maja 2010
PODSTAWY PROTOKOŁU (CLI)
MacBook-Pro:~ mariusz$ telnet 127.0.0.1 11211Trying 127.0.0.1...Connected to 127.0.0.1.Escape character is '^]'.set test 1 0 4abcdSTOREDget testVALUE test 1 4abcdENDset counter 1 0 11STOREDincr counter 12decr counter 11quit
środa, 26 maja 2010
PODSTAWY PROTOKOŁU (PHP)
<?php/** * Przykład: prosta komunikacja z serwerem. */$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);
$memcached->set('test3', 'test3', 3600);$memcached->get('test3');$memcached->add('test4', 'test4', 3600);
?>
środa, 26 maja 2010
ARCHITEKTURA W PRAKTYCE
...
Moduły klienckie
Ruch sieciowy
Rodzaj protokołu
Wykorzystanie pamięci
Ruch sieciowy
Klastrowanie serwerów
Monitoring działania
Strategie cache’owania
LRU, evictions
Podsłuchiwanie komunikacji
Wysoka dostępność
środa, 26 maja 2010
MODUŁY KLIENCKIE DLA PHP
pecl/memcache pecl/memcached
Data pierwszego wydania 2004-06-08 2009-01-29Zależności zewnętrzne libmemcached
Polecenia APPEND/PREPEND ✓
Automatyczna serializacja ✓ ✓
Protokół binarny opcjonalniePolecenie CAS ✓
Kompresja ✓ ✓
Constistent hashing ✓ ✓
Opóźnione pobieranie danych ✓
Polecenie multi-GET ✓ ✓
Support sesji ✓ ✓
Polecenia SET/GET na wskazanym serwerze ✓
Przechowywanie danych liczbowych konwersja ✓
Automatyczne naprawianie kluczy ✓ ✓
Zarządzanie timeout-ami tylko połączenie ✓
środa, 26 maja 2010
STRATEGIE CACHE’OWANIA
• Rozpatrzmy następujące zapytanie
SELECT * FROM table_1 AS t1 JOIN table_2 AS t2 ON (t2.related_id = t1.id)WHERE t1.id BETWEEN 100 AND 200
• Jak aktualizować cache dla tak wykonanego zapytania?
• Czasem taka strategia się jednak sprawdza...
•Osobne klucze vs. tagowanie
środa, 26 maja 2010
STRATEGIE CACHE’OWANIA
• Przykładowe rozwiązanie problemu:
SELECT * FROM table_1 AS t1 WHERE t1.id BETWEEN 100 AND 200// Zapisz pod kluczami t_1_ID wartości poszczególnych rekordów// Zapisz pod innym kluczem listę samych ID
SELECT * FROM table_2 WHERE related_id IN (X1...Xn)// Zapisz pod kluczami t_2_ID wartości poszczególnych rekordów
•W przypadku aktualizacji jakiejkolwiek danej, modyfikowany jest tylko jeden klucz w memcached
środa, 26 maja 2010
PODSŁUCHIWANIE KOMUNIKACJI
• Czasem zachodzi potrzeba analizowania komunikacji pomiędzy procesami PHP a serwerem memcached
• memcached -m 1024 -u root -l 127.0.0.1 -p 11211 -vv
• ngrep -d lo0 port 11211
• wrapper na obiekt klasy Memcache(d)
środa, 26 maja 2010
PODSŁUCHIWANIE KOMUNIKACJI
•Memcached nie udostępnia opcji listowania wszystkich kluczy, ale można skorzystać z narzędzia peep:
$ sudo peep --pretty 2479time | exptime | nbytes | clsid | key | exprd | flushd8658 | 613458 | 272 | 5 | "c3RhdH:171:5" | false | false8658 | 0 | 6 | 1 | "current_c3RhdH:3" | false | false8658 | 613458 | 281 | 5 | "c3RhdH:171:26" | false | false8678 | 95078 | 6 | 1 | "User:1:auth:m4Uq" | false | false8658 | 0 | 8 | 2 | "user_dGltZWxp:4" | false | false8686 | 613486 | 1278 | 9 | "User:1:6" | false | false8658 | 613458 | 1286 | 9 | "User:1:4" | false | false...8658 | 613458 | 283 | 5 | "c3RhdH:171:28" | false | false8658 | 613458 | 277 | 5 | "c3RhdH:171:30" | false | false
dane pochodzą ze strony http://blog.evanweaver.com/articles/2009/04/20/peeping-into-memcached/
środa, 26 maja 2010
MONITORING DZIAŁANIA
STAT pid 83010STAT uptime 29STAT time 1274341051STAT version 1.4.5STAT pointer_size 64STAT rusage_user 0.001817STAT rusage_system 0.004779STAT curr_connections 5STAT total_connections 6STAT connection_structures 6STAT cmd_get 2STAT cmd_set 2STAT cmd_flush 0STAT get_hits 0STAT get_misses 2STAT delete_misses 0STAT delete_hits 0STAT incr_misses 0STAT incr_hits 3
STAT decr_misses 0STAT decr_hits 0STAT cas_misses 0STAT cas_hits 0STAT cas_badval 0STAT auth_cmds 0STAT auth_errors 0STAT bytes_read 133STAT bytes_written 163STAT limit_maxbytes 1073741824STAT accepting_conns 1STAT listen_disabled_num 0STAT threads 4STAT conn_yields 0STAT bytes 72STAT curr_items 1STAT total_items 3STAT evictions 0STAT reclaimed 0
•Monitorowanie serwera za pomocą poleceń STATS
środa, 26 maja 2010
MONITORING DZIAŁANIA
• Integracja z systemami monitorowania środowiska
•Wykresy systemowe pozwalają określić skuteczność cache
środa, 26 maja 2010
ZARZĄDZANIE PAMIĘCIĄ
•Memcached korzysta z algorytmu LRU w obrębie slab klasy
• Expire
• Klucz może zostać usunięty przed wygaśnięciem
• Evictions
•Niebezpiecznie w przypadku wykorzystania memcached jako handlera sesyjnego
środa, 26 maja 2010
PRZECHOWYWANIE WARTOŚCI
• Rozmiar wartości ma znaczenie (klucza także)<?php/** * Przykład: rozmiar wartości. */$data = array( 'key_1' => array( 'value_1_1', 'value_1_2', 'value_1_3' ), 'key_2' => array( 'value_2_1', 'value_2_2', 'value_2_3' ),);
var_dump(serialize($data));var_dump(json_encode($data));
?>
string(162) "a:2:{s:5:"key_1";a:3:{i:0;s:9:"value_1_1";i:1;s:9:"value_1_2";i:2;s:9:"value_1_3";}s:5:"key_2";a:3:{i:0;s:9:"value_2_1";i:1;s:9:"value_2_2";i:2;s:9:"value_2_3";}}"
string(93) "{"key_1":["value_1_1","value_1_2","value_1_3"],"key_2":["value_2_1","value_2_2","value_2_3"]}"
środa, 26 maja 2010
CHECK AND SET
• Równoległe operacje na kluczach, race-conditions
serwer php
serwer php
serwer php
serwer memcached
środa, 26 maja 2010
FLAGI
•Memcached pozwala na przechowywanie wraz z parą klucz-wartość dodatkowych informacji
• Flagi są zapisywanie przez serwer atomowo, wraz z parą
• Implementacja obsługi flag zależy od wersji biblioteki klienckiej
środa, 26 maja 2010
SKALOWANIE
• Rozłożenie kluczy pomiędzy wiele serwerów
• Algorytmy rozpraszania kluczy: modulo, consistent hashing
klucz 11
klucz 27klucz 89
klucz 44
klucz 5klucz 90
serwer memcached 2
klucz 31
klucz 9klucz 13
klucz 51
klucz 99klucz 72
serwer memcached 3
klucz 1
klucz 22klucz 34
klucz 23
serwer memcached 1
klucz 58klucz 62
środa, 26 maja 2010
SKALOWANIE
• Skalowanie memcached od strony PHP
<?php/** * Przykład: Komunikacja z klastrem serwerów. */$memcached = new Memcached();
$memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);$memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$memcached->addServer('127.0.0.1', 11211);$memcached->addServer('127.0.0.1', 11311);$memcached->addServer('127.0.0.1', 11411);$memcached->addServer('127.0.0.1', 11511);$memcached->addServer('127.0.0.2', 11211);$memcached->addServer('127.0.0.3', 11311);
?>
środa, 26 maja 2010
WYSOKA DOSTĘPNOŚĆ
• Projekt Repcached dla memcached 1.2.x, memcached z zasady jest ulotny!
klient
klucz 1
klucz 2klucz 3
klucz 4
klucz 5klucz 6
klucz 1
klucz 2klucz 3
klucz 4
klucz 5klucz 6
get, set, incr, decr
replikacjamaster-master
get, set, incr, decr
środa, 26 maja 2010
OPTYMALIZACJA KOMUNIKACJI
•Memcached jest bardzo szybki, ale czasem barierę wyznacza warstwa sieciowa i ilość zapytań
•Minimalizacja round-tripów, czyli multiGET oraz multiSET
<?php/** * Przykład: 100 x GET */$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);
for ($i = 1; $i <= 100; $i++) { $values[] = $memcached->get('test_' . $i);}
?>
<?php /** * Przykład: 1 x multiGET */$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);
for ($i = 1; $i <= 100; $i++) { $keys[] = 'test_' . $i;}
$values = $memcached->getMulti($keys);
?>
środa, 26 maja 2010
OPTYMALIZACJA KOMUNIKACJI
• Skuteczność operacji multiGET/multiSET zależy od sposobu rozrzucania kluczy pomiędzy serwery
• Jeśli dysponujemy 20 serwerami memcached i zapisujemy 20 kluczy, w najgorszym przypadku wykonujemy 20 pojedynczych SET-ów
• Analogicznie jest z pobieraniem danych
środa, 26 maja 2010
OPTYMALIZACJA KOMUNIKACJI
•Moduł pecl/memcached umożliwia przejście na protokół binarny
• Pozwala to zaoszczędzić cenne zasoby<?php/** * Przykład: Opcje połączenia. */$memcached = new Memcached();
// Przed połączeniem z serwerem!$memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
$memcached->addServer('127.0.0.1', 11211);
var_dump($memcached->getOption(Memcached::OPT_BINARY_PROTOCOL));
?>
środa, 26 maja 2010
OPTYMALIZACJA KOMUNIKACJI
•Opóźnione pobieranie kluczy
<?php/** * Przykład: Opóźnione pobieranie kluczy. */$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);$memcached->get('int', 99);$memcached->get('string', 'a simple string');$memcached->get('array', array(11, 12));
var_dump($memcached->getDelayed(array('int', 'array'), true));?>
•Opóźnione zapisywanie wartości
• Przydatne np. przy wykorzystaniu memcached jako handlera sesyjnego
środa, 26 maja 2010
DOGPILE EFFECT
• Czym jest dogpile effect? Kiedy może wystąpić? Jak się bronić?
serwer php
serwer php
serwer php
serwer memcachedx
środa, 26 maja 2010
ROZWIĄZANIA ALTERNATYWNE
•MemcacheDB
• Trwały silnik KV oparty o bazę danych BerkeleyDB
• Redis
• Bardzo wydajny, trwały silnik KV implementujący protokół memcachedPosiada wsparcie dla złożonych struktur danych
środa, 26 maja 2010
DZIĘKUJĘ ZA UWAGĘ.PYTANIA?
środa, 26 maja 2010