Django Cache dei contenuti con Nginx backend uWsgi

Concetti generali:

Benefici:

  • Riduzione del carico sui backend
  • Possibilità di scalare fino a centinaia di richieste al secondo.

Schema di base

HTTP Client --> Nnginx -->  uWsgi
                 |------> Cache

Configurazione

Le direttive esterne al blocco server

uwsgi_cache_path : percorso dove verrano salvati in cache, questa direttiva risiede fuori dal blocco Server.

A sua volta ha una serie di sotto parametri:

  • levels: quante sottodirectory crerà nginx per gestire i suoi file di cache.
  • keys_zone: definisce un pezzo di Memoria condivisa di dimensione variabile dove vengono salvati chiavi e metadati. Ongi volta che viene chiesta una pagina nginx controlla prima questa area di memoria, se la pagina è in cache recupera la chiave che utilizzerà per servire i contenuti salvati nel percorso cache_path definito nella direttiva cache_path.
  • inactive: dopo quanto un tempo un contenuto inattivo ( non chiamato ) sara rimosso dalla cache.
     
wsgi_cache_path /var/cache/nginx/cache/crazylinux  levels=1:2 keys_zone=crazylinux:16m inactive=60m;

server {
    listen     443 ssl;
    server_name crazylinux.it;
    ...
}

uwsgi_cache_path: /var/cache/nginx/cache/crazylinux: I file verranno salvati in /var/cache/nginx/cache/crazylinux.

levels=1:2 : Con massimo due livelli di direcory:

Infatti andando ad esplorare il contentuto di /var/cache/nginx/cache/crazylinux troviamo

[root@myserver crazylinux]# du *
8       2/6d
12      2
8       7/21
12      7
12      9/7d
8       9/9d
24      9
8       b/df
12      b
8       c/c0
12      c

keys_zone=crazylinux:16m : ho dichiarato una zona di memoria che si chiama crazylinux di 16m. Si potrebbe traquillamente ridurre, in un 1m vengono salvate fino ad 8000 chiavi.

inactive=60m: Se una pagina non pagina non viene chiamata per 60 minuti la chache verrà invalidata

Passiamo alla configurazione al intermo del blocco server

Per una visione completa di tutte le direttive possiamo consultare direttamente la documentazione ufficiale http://nginx.org/en/docs/http/ngx_http_uwsgi_module.html

  • uwsgi_cache: Definisce la zona di shared memory che verrà usata dalla cache ( La configuriamo come quella definita in precedenza )
  • uwsgi_cache_revalidate: Definisce la possibilitàdi rivalidare la cache
  • uwsgi_cache_key: Dinisce La chiave per la cache
  • uwsgi_cache_valid: Difinisce quali risposte mettere in cache e per quanto.

Possiamo aggiungere lo stato della cache nel Header HTTP:

  • add_header: Possiamo Aggiungere al Header lo stato della cache.
server {
    ...
    location / {
		...
		include     /etc/nginx/uwsgi_params;
        	uwsgi_pass  unix:///run/uwsgi/agreco_blog.sock;

		#client cache
		uwsgi_cache crazylinux;
		uwsgi_cache_revalidate on;
		uwsgi_cache_key $uri;
		uwsgi_cache_valid any 1h; #Or whatever value you want
		add_header X-Cache-Status $upstream_cache_status ;
	}
}

Atri possibili valori assegnabili a uwsgi_cache_valid

uwsgi_cache_valid 200 302 10m;
uwsgi_cache_valid 301      1h;
uwsgi_cache_valid any      1m;

Per rendere effettive le modifiche, possiamo riavviare il server.

# check config
nginx -t
# Restart
systemctl restart nginx

Verifichiamo il funzionamento

Per veficare il corretto funzionamento possiamo eseguire una cUrl e analizare gli Header HTTP

$ curl -I https://crazylinux.it/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Mon, 09 Oct 2017 20:51:09 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 5409
Connection: keep-alive
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
Expires: Tue, 10 Oct 2017 20:51:09 GMT
Cache-Control: max-age=86400
X-Cache-Status: MISS

Osservando gli Header della risposta vedremo che il parametro X-Cache-Status: è uguale ad MISS quindi la pagina non è in cache.

Se rieseguiamo la chiamata.

$ curl -I https://crazylinux.it/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Mon, 09 Oct 2017 20:52:33 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 5409
Connection: keep-alive
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
Expires: Tue, 10 Oct 2017 20:52:33 GMT
Cache-Control: max-age=86400
X-Cache-Status: HIT

Vedremo che nel Header il parametro X-Cache-Status: è cambiato in  HIT la pagina è in cache.

Bypassare la cache

Potrebbe essere necessario escludere alcuni url dalla cache o che la cache venga scavalcata.
Adesempio voglio scavalcare la cache per il mio articolo https://crazylinux.it/it/post/installazione-grafana/

Testando una cUrl  lo stato della pagine

$ curl -I https://crazylinux.it/it/post/installazione-grafana/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Sun, 22 Oct 2017 12:05:22 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6539
Connection: keep-alive
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
Expires: Mon, 23 Oct 2017 12:05:22 GMT
Cache-Control: max-age=86400
X-Cache-Status: HIT

Inziamo configurado nel blocco server, tutti gli url che vogliamo bypassare.

if ( $request_uri ~ /it/post/installazione-grafana/ ) {set $nocache 1; }
    location / {
                uwsgi_pass  unix:///run/uwsgi/agreco_blog.sock;

                uwsgi_cache crazylinux;
                uwsgi_cache_revalidate on;
                uwsgi_cache_key $uri;
                uwsgi_cache_bypass $nocache;
                uwsgi_no_cache $nocache;
                uwsgi_cache_valid any 1h; #Or whatever value you want
                add_header X-Cache-Status $upstream_cache_status ;
        }

Riavviamo il nginx, e verifichiamo che la cache venga bypassata.

$ curl -I https://crazylinux.it/it/post/installazione-grafana/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Sun, 22 Oct 2017 12:22:09 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6539
Connection: keep-alive
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
Expires: Mon, 23 Oct 2017 12:22:09 GMT
Cache-Control: max-age=86400
X-Cache-Status: BYPASS

Cache Purge

Un metodo molto rapido per il purge della cache è questo script bash, andra lanciato a mano tramite ssh, in aternativa scriere uno script CGI / UWSGI.

git clone git://github.com/perusio/nginx-cache-purge.git

Le istruzioni sul funzionamento si trovano direttamente nel readme del repo.

perusio/nginx-cache-purge

In alternativa si può installare il modulo, ma non ne parlerò in questo articolo.

FRiCKLE/ngx_cache_purge