Łukasz C.

Łukasz C. Senior Technical
Architect

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Hej,

niedawno byłem ofiarą wykop-efektu i stwierdziłem, że czas najwyższy wziąć się za temat cachowania.

Po kilku godzinach zawziętego klepania i testowania wyszło mi takie oto coś:

http://files.ognisco.com/kickasscache/kickasscache-201...

aby tego użyc trzeba:
1) mieć moduł apc (php-apc: na ubuntu: apt-get install php-apc)
2) przykładowy kod, index.php:

<?php
require 'KickAssCacheApc.php';
$cache = new KickAssCacheApc();
$cache->capturePage();

// tutaj reszta kodu dowolnej aplikacji w php.

Nie chwaliłbym się prostą klasą w php gdyby nie wyniki:

to coś wyciąga ponad 2 tysiące requestów na sekunde! :O
Zadowolony byłbym gdyby było nawet 100req/sec ale nie, aż tyle :D

Co do testowania:
- Zend Framework, Doctrine, PostgreSQL (o to: http://cyckizrana.pl)
- apache benchmark: ab -n 100000 -c 200 http://localhost/cyckizrana/web/cycki-dnia
- apache2, php5.3, ubuntu 32bit (standardowa konfiguracja)
- core2duo 2.4ghz, 2gb ram, hdd 7500rpm

Wyniki:
Requests per second: 2079.79 [#/sec] (mean)
Time per request: 96.164 [ms] (mean)
Time per request: 0.481 [ms] (mean, across all concurrent requests)
Transfer rate: 36834.99 [Kbytes/sec] received

pełny raport jest tutaj: http://files.ognisco.com/kickasscache/kickasscache-201...

konfiguracja cache: ttl=5 randomfactor=7

Moglibyście obadać czy też macie takie wyniki z kosmosu?
Mam nadzieje, że się to komuś przyda :)

Licencja whiskeyware [;
Wojciech Soczyński

Wojciech Soczyński Programista
eksplorator -
blog.wsoczynski.pl

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Takie wyniki to nic szczególnego, biorąc pod uwagę to, że pewnie w razie kiedy strona już znajduje się w cache to nie wykonujesz skryptu tylko serwujesz statyczny html. Pewnie by było jeszcze szybciej jak byś zastosował tandem reverse proxy(np. nginx) + memcached.

konto usunięte

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Varnish wyciąga kilkadziesiąt tysięcy / sec ;-) A bazuje na cookie, typ requestu etc więc jest bardziej inteligentny.
Łukasz C.

Łukasz C. Senior Technical
Architect

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

nie zdziwilbym sie gdyby memcache byl wolniejszy (memcache + php), bo komunikacja jest po sokecie i dziala jako osobny proces, natomiast apc siedzi jako czesc aktualnego procesu php, co do wynikow to cache sam w sobie daje jakies 500req/sec natomiast dopiero cos ala mutex sprawilo ze wyniki wskoczyly na 2k, dlaczego?
jak strona jest juz w cache to poprostu ja serwujesz ale problem pojawia sie gdy cache trzeba odswierzyc, w php nie ma w ogole konkurencyjnosci wiec jak benchmark wysyla naraz 200 requestow to napewno kilkadziesiat z nich odpali process php przzez cos nagle wydajnosc spadnie drastycznie o ile w gole serwer to wytrzyma (bez cache mialem 8 req/sec), w mojej implementacji jest cos jak thread race, tzn: pierwszy powinien ustawic mutex, a pozostale maja czekac az mutex sie zwolni i beda mogly serwowac strone z cache. W php nie da sie zrobic tradycyjnego mutexa bo nie ma w ogole wsparca dla wielu procesow/watkow, wiec dziala to troche losowo i nie daje gwarancji ze nie uruchomi sie wiecej jak jeden proces php ktory wykona strone, natomiast z testow jasno wynika ze ta implementacja to ograniczyla:

100k requestow
200 na raz
0 zlych odpowiedzi :)

co do innych cache, oczywiscie, statyczny cache bedzie najszybszy bo mozna go serwowac lekkim serwerem i wtedy kilkadziesiat req/sec nie jest problemem, w praktyce jednak trzeba to i zaprojektowac i wdrozyc, natomiast moj kod to 3 linijki ktore jako tako dzialaja :)Łukasz C. edytował(a) ten post dnia 09.06.11 o godzinie 09:53
Wojciech Soczyński

Wojciech Soczyński Programista
eksplorator -
blog.wsoczynski.pl

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Łukasz C.:
nie zdziwilbym sie gdyby memcache byl wolniejszy (memcache + php), bo komunikacja jest po sokecie i dziala jako osobny proces, natomiast apc siedzi jako czesc aktualnego procesu php, co do wynikow to cache sam w sobie daje jakies 500req/sec natomiast dopiero cos ala mutex sprawilo ze wyniki wskoczyly na 2k, dlaczego?
jak strona jest juz w cache to poprostu ja serwujesz ale problem pojawia sie gdy cache trzeba odswierzyc, w php nie ma w ogole konkurencyjnosci wiec jak benchmark wysyla naraz 200 requestow to napewno kilkadziesiat z nich odpali process php przzez cos nagle wydajnosc spadnie drastycznie o ile w gole serwer to wytrzyma (bez cache mialem 8 req/sec), w mojej implementacji jest cos jak thread race, tzn: pierwszy powinien ustawic mutex, a pozostale maja czekac az mutex sie zwolni i beda mogly serwowac strone z cache. W php nie da sie zrobic tradycyjnego mutexa bo nie ma w ogole wsparca dla wielu procesow/watkow, wiec dziala to troche losowo i nie daje gwarancji ze nie uruchomi sie wiecej jak jeden proces php ktory wykona strone, natomiast z testow jasno wynika ze ta implementacja to ograniczyla:

100k requestow
200 na raz
0 zlych odpowiedzi :)

co do innych cache, oczywiscie, statyczny cache bedzie najszybszy bo mozna go serwowac lekkim serwerem i wtedy kilkadziesiat req/sec nie jest problemem, w praktyce jednak trzeba to i zaprojektowac i wdrozyc, natomiast moj kod to 3 linijki ktore jako tako dzialaja :)

Btw. mówiłem o cache'u, który całkowicie pomija PHP (i apache'a) kiedy strona jest już wygenerowana. W każdym razie pomysł z mutexami ciekawy. Tak nawiasem, jeżeli chodzi o wątki to zawsze można postawić PHP na fast cgi i wtedy zdaje się można ich używać (pthread).Wojciech Soczyński edytował(a) ten post dnia 09.06.11 o godzinie 10:04
Tomasz Zadora

Tomasz Zadora programuję

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Łukasz C.:
[...]
pojawia sie gdy cache trzeba odswierzyc, w php nie ma w ogole konkurencyjnosci wiec jak benchmark wysyla naraz 200 requestow to napewno kilkadziesiat z nich odpali process php przzez cos nagle
[...]

Można ten problem chyba rozwiązać przez dodatkową zmienną w cache służącą synchronizacji dostępu do "zasobu" który trzeba odświeżyć - w tym sensie, żeby tylko jeden request w danym momencie zapisywał dany zasób a reszta czekała aż się to stanie.

Można to tak zrobić, że nie będzie blokować zapisu/odczytu innych zasobów.
Łukasz C.

Łukasz C. Senior Technical
Architect

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

heh no dokladnie to napisalem, tylko ze w praktyce w php to nie jest takie hop siup do napisania bo nie ma w ogole synchronizacji, i wszelkiego rodzaju locki itp nie sa dokladne
Tomasz Zadora

Tomasz Zadora programuję

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Łukasz - racja, że to nie jest proste :)

Mam sobie podobną klasę do Twojej już od pewnego czasu gdzie można wybrać sposób/storage keszu: pliki lub memcached ale dodam do tego chyba APC - właśnie dlatego, że nie trzeba komunikacji po sockecie.

W każdym razie ja robię z mutexami tak:

Dla każdego zasobu o określonym kluczu istnieje drugi malutki zasób - mutex (o kluczu identycznym jak klucz zasobu tylko z jakimś prefixem).

Po za tym oprócz klucza jest jeszcze "grupa" - to głównie dla keszu w sytemie plików bo oznacza wtedy katalog.

Druga sprawa: keszuje nie tyle całą stronę (mogę też tak zrobić) ale raczej mam "przepisy" (np. w postaci kodu eval) na wykonanie/stworzenie zasobu - i teraz to może być jakaś mała część strony lub zestaw danych tworzony przez jakąś klasę, w momencie jak zasobu brak albo jest przeterminowany, ten kod eval się wykonuje (blokując mutex tylko dla tego zasobu) - musi tylko stworzyć określoną zmienną (np. $obj) która następnie będzie zachowana w cache.

Tworzy się dość dużo mutexów ale zysk jest taki że jest dobra "jednoczesność" - mało blokowania przy dużej ilości zapisów na raz do różnych zasobów w cache.

Generalnie taka dowolna metoda która podlega keszowaniu ma najczęściej jako argument zmieną $cache domyślnie ustawioną na "true", w pierwszej kolejności stara się pobrać zasów z keszu (jeżeli $cache = true) jeżeli się nie uda tworzy kod eval do siebie samej z argumentem $cache = false. Silnik keszu wywołuje ponownie metodę (z $cache = false), tworzy zasób, zapisuje i zwraca z tej właśnie metody.


function &getSomething($arg1, $arg2, $cache = true, $cacheTime = 600)
{
if ($cache)
{
$key = 'mykey-'.$arg1.'-'.$arg2;
$group = 'some-group';
$eval = '$obj =& getSomething($arg1, $arg2, false)';
return Cache::getByEval($key, $group, $eval, $cacheTime);
}

....tutaj działanie które zwróci cokolwiek....
}
Tomasz Zadora edytował(a) ten post dnia 09.06.11 o godzinie 10:31
Dawid Rokita

Dawid Rokita CTO picAds.pl

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Poprawcie mnie jeżeli się mylę...
APC zadziała tylko na lokalnym serwerze, a memcache pozwoli współdzielić cache między X serwerów ... moim zdaniem to bardziej rozwojowe podejście.

Z doświadczenia wiem że dobrze jest cache'ować na kilku poziomach, przykładowo wyniki z DB i wyniki renderowania template'ów ... wiem że to skrajny przykład ale co jeżeli np 90% cache wygaśnie w jednej chwili to wszystko pójdzie z DB i serwis klęknie.
Łukasz C.

Łukasz C. Senior Technical
Architect

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

ale memcache tez nie jest workiem bez dna a pozatym jezeli skalujesz i np: siedzi load balancer to w przypadku gdy cache id jest generowany losowo bedziesz mial inne wyniki dla kazdej maszyny, ja bym cache i php stawial jednak na tej samej maszynie
Paweł Spychalski

Paweł Spychalski Senior Frontend
Developer, Home24

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Dawid Rokita:
Poprawcie mnie jeżeli się mylę...
APC zadziała tylko na lokalnym serwerze, a memcache pozwoli współdzielić cache między X serwerów ... moim zdaniem to bardziej rozwojowe podejście.

Nie mylisz się. Mało tego, memcached pozwala na shardowanie, współdzielenie danych pomiędzy modułami napisanymi w różnych językach i tym podobne. Czasami trzeba trochę pokombinować i przezwyciężyć kilka problemów, ale samo podejście jest bardzo rozwojowe
Michał Gruchała

Michał Gruchała Skalowalność,
wydajność,
niezawodność

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

konkurencyjnosci wiec jak benchmark wysyla naraz 200 requestow to napewno kilkadziesiat z nich odpali process php przzez cos nagle wydajnosc spadnie drastycznie o ile w gole serwer to wytrzyma (bez cache mialem 8 req/sec), w mojej implementacji jest cos jak thread

to sie nazywa "dog-pile effect". varnish prosto to zalatwia (taki hint)
Dawid Rokita

Dawid Rokita CTO picAds.pl

Temat: 2 tys requestow na sekunde w PHP (zend + doctrine) :)

Łukasz C.:
ale memcache tez nie jest workiem bez dna a pozatym jezeli skalujesz i np: siedzi load balancer to w przypadku gdy cache id jest generowany losowo bedziesz mial inne wyniki dla kazdej maszyny, ja bym cache i php stawial jednak na tej samej maszynie

Ale w php można sobie zdefiniować pulę serwerów, a to że jeden proces memcache ma ograniczenie 4Gb to nie problem, przecież można odpalić kilka procesów na kilku portach i po sprawie.

"przypadku gdy cache id jest generowany losowo" - trzeba tak programować żeby cacheid jednoznacznie identyfikowało zasób według odpowiednich kryteriów decydujących o jego unikalności (np: id usera, podstrona, rodzaj sortowania, kategoria itd)Dawid Rokita edytował(a) ten post dnia 13.06.11 o godzinie 11:08



Wyślij zaproszenie do