Skip to main content
01 Feb

Kako smo popravili crometeo.hr - 2. dio: FastCGI cache

U originalnom tekstu o zahvatima na web portalu udruge Crometeo opisali smo koje smo radnje poduzeli kako bi portal profunkcionirao na prihvatljivo brz način. Testiranja su pokazala kako keširanje pomoću plugina WP Super Cache nije najoptimalnije pa smo odlučili promijeniti metodologiju. Naime, s obzirom da je keširanje osim putem plugina moguće raditi i na server levelu, odlučili smo se za tu opciju.

Nginx web server je u stanju keširati podatke pristigle iz FastCGI aplikacija na jednostavan način. Osim jednostavnosti i robusnosti rješenja, čini se da ono pruža i najbolje performanse u usporedbi sa ostalim cache izvedbama (različiti Wordpress pluginovi i slično).

Nakon deinstalacije WP Super Cache plugina, FastCGI cache za portal smo omogućili određivanjem sljedećih direktiva u Nginx konfiguraciji:

    fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:256m inactive=60m;
    fastcgi_cache_key $host$request_method$request_uri;

Prva linija je ključna i ona kaže da se putanja na kojoj će se spremati keširani zahtjevi nalazi u /var/run/nginx-cache, definira strukturu direktorija, ime i veličinu zone te vrijeme trajanja spremljenih podataka u kešu. S obzirom da se putanja /var/run nalazi u tmpfs objektu koji je dio radne memorije, keširani podaci se zapravo spremaju izravno u RAM umjesto na disk. Takav setup omogućuje značajno brže spremanje i čitanje podataka u odnosu na operacije preko diska.  keys_zone=WORDPRESS:256m znači da je ime zone WORDPRESS, a maksimalna veličina svih keširanih podataka 256 megabajta, a inactive=60m nam govori da će svi podaci kojima nije pristupano 60 minuta biti izbrisani iz keša automatski.

Nakon što smo definirali prostor za cache i njegova osnovna svojstva, potrebno je upotrijebiti sam cache prostor unutar server {} bloka u nginx konfiguraciji. To ćemo napraviti za php zahtjeve pomoću sljedeće konstrukcije:

    location ~ [^/]\.php(/|$) {
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        if (!-f $document_root$fastcgi_script_name) {
            return  404;
        }
        fastcgi_pass    127.0.0.1:9004;
        fastcgi_index   index.php;
        include         /etc/nginx/fastcgi_params;
        fastcgi_cache_bypass    $skip_cache;
        fastcgi_no_cache        $skip_cache;
        fastcgi_cache            WORDPRESS;
        fastcgi_cache_valid        60m;            
    }

Ovaj blok usmjerava php zahtjeve prema FastCGI serveru koji u ovom slučaju sluša na portu 9004. U bloku se nalazi informacija o cache zoni koja će se koristiti za keširane objekte (WORDPRESS), te što uraditi za podacima koji se ne smiju keširati (varijabla $skip_cache koja poprima vrijednost =1 ako keširanje nije poželjno).

Kako bi odredili za koje zahtjeve je keširanje poželjno a za koje nije, definirat ćemo varijablu $skip_cache sa vrijednošću =0 onda kad želimo keširanje, te =1 kad ne želimo.

Budući da želimo keširanje za većinu zahtjeva, unutar server {} bloka postavit ćemo default vrijednost $skip_cache =0:

    set $skip_cache 0;

Zatim, definiramo zahtjeve za koje ne želimo keširanje, kao na primjer ako u zahtjevu imamo POST metodu:

    if ($request_method = POST) {
        set $skip_cache 1;
    }

Slične blokove ćemo dodati za sve ostale zahtjeve za koje ne želimo keširanje. Drugi primjer gdje smo onemogućili keširanje u potpunosti je forum. Iako je moguće onemogućiti keširanje samo za logirane korisnike, zbog naravi crometeo foruma smatramo da ga je bolje isključiti u potpunosti za sve posjetitelje. Štoviše, aplikacija phpbb na kojoj se "vrti" crometeo forum dovoljno je brza i ne prestavlja veliko opterećenje za server pa keširanje nije potrebno:

    location /forum {
        set $skip_cache 1;
    }

 

Konačno, uz sve ostale konfiguracijske postavke, nginx konfiguracija sa funkcionalnim FastCGI cache sistemom u RAM-u, za crometeo.hr domenu izgleda ovako:

 

# FastCGI cache (in tmpfs)
    fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:256m inactive=60m;
    fastcgi_cache_key $host$request_method$request_uri;

server {
    listen      148.251.250.22:80;
    listen      148.251.250.22:443 http2 ssl;
    server_name crometeo.hr www.crometeo.hr;
    root        /home/cromethr/web/crometeo.hr/public_html;
    index       index.php index.html index.htm;
    access_log  /var/log/nginx/domains/crometeo.hr.log combined;
    access_log  /var/log/nginx/domains/crometeo.hr.bytes bytes;
    error_log   /var/log/nginx/domains/crometeo.hr.error.log error;

    ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
    ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
    ssl_dhparam /etc/nginx/dhparams.pem;

    set $skip_cache 0;

#   POST requests and URLs with a query string should always go to PHP
    if ($request_method = POST) {
        set $skip_cache 1;
    }
    if ($query_string != "") {
        set $skip_cache 1;
    }

#   Don't use the cache for logged-in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass
        |wordpress_no_cache|wordpress_logged_in") {
            set $skip_cache 1;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

# Don't cache forum...
    location /forum {
        set $skip_cache 1;
    }

# But, cache wordpress with FastCGI cache
    location ~ [^/]\.php(/|$) {
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        if (!-f $document_root$fastcgi_script_name) {
            return  404;
        }
        fastcgi_pass    127.0.0.1:9004;
        fastcgi_index   index.php;
        include         /etc/nginx/fastcgi_params;
        fastcgi_cache_bypass    $skip_cache;
        fastcgi_no_cache        $skip_cache;
        fastcgi_cache            WORDPRESS;
        fastcgi_cache_valid        60m;            
    }

    location ~ /purge(/.*) {
        fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
    }

    location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|css|js)$ {
        access_log off;
        log_not_found off;
        expires max;
    }

    location = /robots.txt {
        access_log off;
        log_not_found off;
    }

    error_page  403 /error/404.html;
    error_page  404 /error/404.html;
    error_page  500 502 503 504 /error/50x.html;

    location /error/ {
        alias   /home/cromethr/web/crometeo.hr/document_errors/;
    }

    location ~* "/\.(htaccess|htpasswd)$" {
        deny    all;
        return  404;
    }

    location ~* wp-config.php {
        deny all;
    }

    location /vstats/ {
        alias   /home/cromethr/web/crometeo.hr/stats/;
        include /home/cromethr/web/crometeo.hr/stats/auth.conf*;
    }

    include     /etc/nginx/conf.d/phpmyadmin.inc*;
    include     /etc/nginx/conf.d/phppgadmin.inc*;
    include     /etc/nginx/conf.d/webmail.inc*;

    include     /home/cromethr/conf/web/nginx.crometeo.hr.conf*;
}