Jak przyspieszyć działanie TYPO3 przy pomocy nginx'a.

UWAGA. Nowa wersja i nowa podstrona dedykowana tylko evo_nginx_boost techblog.evo.pl/evo_nginx_boost-extension/ Teraz evo_nginx_boot może pracować bez użycia NGINX'a. Wymagane jest TYPO3 i memcache!

TYPO3 cache

Kwestia wydajności TYPO3 była omawiana wiele razy. Znalazłem wiele różnych tricków, które pozwalają przyśpieszyć czas generacji strony między innymi moduł  nc_staticfilecache czy dmc_highperformance. Najnowsza wersja TYPO3, która obecnie jest w fazie alpha radykalnie zmienia podejście do cachowania, dając nam do wyboru różne mechanizmy wsparcia jak file, memcache, database, czy apc.

Problem

Wszystkie powyższe rozwiązania z wyjątkiem nc_staticfilecache mają jedną wspólną rzecz: aby odczytać cache należy wywołać proces php i odczytać scachowane dane, sparsować, a następnie wysłać do przeglądarki.

Zróbmy prosty test z wykorzystaniem narzędzia ab. Sprawdzimy ilość zapytań na sekundę z wykorzystaniem złożonej witryny.

zaznacz
  1.  
  2. ab -n 100 -c 1 <a href="http://localhost/" >localhost</a>
  3. Server Software:        Apache/2.2.6 Server Hostname:       
  4. localhost Server Port:            80
  5. Total transferred:      5064709 bytes
  6. HTML transferred:       5031914 bytes
  7. Requests per second:    1.02 [#/sec] (mean)
  8. Time per request:       976.265 [ms] (mean)
  9. Time per request:       976.265 [ms] (mean, across all concurrent requests)
  10. Transfer rate:          50.66 [Kbytes/sec] received

Ilość zapytań na sekundę 1.02!

Co się stanie jeśli nasz serwis będzie musiał obsłużyć 1000 takich zapytań na sekundę? Nawet z  najbardziej wydajnym mechanizmem cachowania, każde wywołanie parsera PHP do odczytania danych spowoduje bardzo duży load na serwerze.

Nginx

Z pomocą może nam przyjść serwer proxy NGINX. Nie jest on może nowym odkryciem, ale sprytne połączenie go z TYPO3 spowoduje wzrost wydajności ponad 200x! Opisane przeze mnie rozwiązanie obsługuje ruch użytkowników zalogowanych i niezalogowanych, uwzględnia zmianę strony po zalogowaniu oraz różne ustawienia cache w TYPO3.

Teraz do rzeczy. Oto założenia naszej instalacji:

Nginx Typo3 and Memcache

 

Użytkownik wywołuje stronę. Nginx sprawdza jego cookie. Jeśli ustawione jest cookie o nazwie nginx_boost_noCache wtedy zapytanie jest wysyłane odrazu do Apacha a później do TYPO3 z pominięciem memcache. Dzięki temu cookie możemy łatwo kontrolować kiedy bezwzględnie należy wyłączyć cachowanie w memcache. Może to zrobić w dowolnej wtyczce w naszym systemie. Poniżej  wyciąg z konfiguracji nginx do obsługi takiego przypadku

zaznacz
  1.  
  2. if ($http_cookie ~* "nginx_boost_noCache=1") { proxy_pass  <a href="http://domain" >domain</a>; break; }

W sytuacji kiedy nginx nie znajdzie cookie nginx_boost_noCache, sprawdza czy w memcache istnieje scachowana strona. Jako klucz używa $request_uri.

zaznacz
  1.  
  2. # set default memcache key set
  3. $memcached_key $request_uri;
  4. # Check if local memcached server can answer this request
  5. default_type text/html;
  6. memcached_pass 192.168.168.3:11211;

Jeśli nasza strona nie znajduje się w memcache, nginx ponownie wysyła zapytanie do apacha. Apache wywołuje TYPO3, generuje stronę, następnie wtyczka evo_nginx_boost  zapisuje ją do memcache z memcache_key takim samym jak żądany url. 

$memcache_key  = "domain/about-us"

Kolejne wywołanie tej strony zostanie wysłane odrazu z memcache bez potrzeby uruchamiania procesu PHP.

Nasza wtyczka w pełni uwzględnia ustawienia czasu cachowania w TYPO3 dla każdej ze stron, odcztuje też wartość cache_period. Jeśli w TYPO3 nie zostało nigdzie ustawiony czas cachowania to pobieramy wartość defaultową z konfiguracji wtyczki.

Co jeśli użytkownik się zaloguje?

Wszystko zależy od nas. Możemy w nginx i evo_nginx_boost wyłączyć zupełnie cachowanie dla zalogowanych. My jednak analizując nasze potrzeby i statystyki strony doszliśmy do wniosku, że zalogowany użytkownik często w ramach jednej sesji ogląda i wraca do tych samych stron. Zmiana musi nastąpić  kiedy użytkownik wyśle żądanie POST, np: napisze komentarz, czy artykuł w blogu. W takiej sytuacji korzystamy z hooka w clasie class.tslib_fe.php - initFEuser.

Jeśli użytkownik się zaloguje ustawiamy cookie nginx_boost_fe_user o wartosci takiej samej jak fe_typo_user.

$memcache_key = "domain/blogs/us1b27c2c23bdb600912561e08a7e4886b"

Natomiast po wysłaniu POSTa lub innej operacji, która wymaga odświeżenia widoku dodajemy do tej wartości wersje. Wtyczka evo_nginx_boost następnie zapisuje do memcache  nową wersję strony.

$memcache_key = "domain/blogs/us1b27c2c23bdb600912561e08a7e4886b_1"

Po 5min wersja strony się przedawni i nginx wyśle nowe żądanie do Apacha i Typo3. Jeśli w tym czasie inny użytkownik doda  komentarz do bloga to zobaczymy to po 5min.

Warto też ustawiać małe czasy cachowania dla stron w których dane są często zmieniane. W serwisie społecznościowym o dużym obciążeniu widok strony usuwamy z cache co 1-5min to spokojnie nam wystarczy do obsłużenia bardzo dużego ruchu.

Teraz czas na testy ab dla powyższego rozwiązania.

zaznacz
  1.  
  2. ab -n 100 -c 1 <a href="http://localhost/" >localhost</a>
  3. Server Software:        nginx/0.6.35
  4. Server Hostname:        localhost
  5. Server Port:            80
  6. Total transferred:      10103800 bytes
  7. HTML transferred:       10089200 bytes
  8. Requests per second:    400.05 [#/sec] (mean)
  9. Time per request:       2.500 [ms] (mean)
  10. Time per request:       2.500 [ms] (mean, across all concurrent requests)
  11. Transfer rate:          39468.58 [Kbytes/sec] received

Ilość zapytań na sekundę 400.05!

Opis konfiguracji evo_nginx_boost

Property:

Data type:

Description:

Default:

enable

string

enable disable memcaching

1

forceTimeoutToAllPages

int

set default memcache expiration time (has priority over TYPO3 setting)

0

disableCacheForLoogedUsers

int

enable/disable memcaching for logged users

0

cleanOnClearAllCache

int

if set, memcache is cleared when backend user click clear cache

setPageCacheTimeout OverrideAllTypoSettings

int

if you enable this option, you can override all expires time from your user_int extension, fg if you have page with four extensions and each extension calls static function: if (method_exists('tx_evo_nginx_boost', 'setPageCacheTimeout') tx_evo_nginx_boost::setPageCacheTimeout($timeout); evo_nginx_boost set expire time to the lowest value set in all 4 plugins

1

_mainServerIP

string

memcache server ip

_mainServerPort

string

memcache server port

_mainServerPersistent

int

enable persistant connection

1

_mainServerTimeout

string

memcache server connection timeout

1

memcacheSignature

int

add signature to end o pages

1

memcacheSignatureText

string

text of signature fg "CACHED BY ME :)". If you set memcacheSignature = 1 time of expiration is added to the end of memcacheSignatureText

1

excludedUrls

array

Set in ext_localconf. This is array of urls which should be excluded from memcaching. Let say you have confirmation message after successfuly saving post in user's blog. Page with message "your post was saved" will be memcached. You can add parameter message=1 and put this in array. Evo_nginx_boost exclude this url from memcaching.

1

Wtyczka posiada również moduł BE, w którym możemy obserwować wszystkie parametry związane z serwerem memcache. W opcji cachedump można sprawdzić jakie strony z jakim memcache key zostały zapisane:

 

Backend module

 

Całe rozwiązanie było testowane na bardzo skomplikowanej witrynie z dużą ilością różnych rozszerzeń USER i USER_INT. Czekamy na uwagi i sugestie. 

Pliki do pobrania:

Uwaga:

Wersja nginxa dostępna przez apt-get w  dystrybucji ubunt 8.04.1 posiada błąd.

Bugfix: a segmentation fault occurred in worker process, if the  "memcached_pass" and "if" directives were used in the same location.

Należy pamiętać, aby czas serwera był taki sam jeśli nginx i apache są na różnych maszynach :)

blog comments powered by Disqus