Document Actions

Nginx come reverse proxy di plone

Note: Return to tutorial view.

Breve guida alla configurazione di Nginx come reverse proxy di plone. Una valida alternativa ad Apache in caso siti ad alto traffico.

Introduzione

In questo tutorial affronteremo la configurazione di nginx in come reverse-proxy (senza cache) di Plone.


Nella gestione di un sito "di produzione" è raramente sufficiente il solo utilizzo di Plone. Spesso si rivela necessario (per motivi prestazionali e legati alla gestibilità delle risorse) mettere in piedi una infrastruttura costituita da parecchi elementi:  zeo server, caching proxy server, load balancer ecc.

Uno degli elementi ricorrenti di queste configurazione è il classico apache utilizzato come reverse-proxy.

Lo scopo di mettere un reverse-proxy è fondamentalmente quello di gestire più host virtuali oppure di fornire una cache (nel caso di squid o varnish).

In questa guida sostituirò nginx ad apache nel ruolo di reverse-proxy senza cache allo scopo di esplorarne le caratteristiche, la sua configurazione con plone e le prestazioni.

Nginx

Come riportato nel wiki ufficiale
"Nginx ("engine x") è un server HTTP ad alte prestazioni con possibilità di operare come reverse proxy e IMAP/POP3/SMTP proxy server. Nginx è stato scritto Igor Sysoev per Rambler.ru, il secondo sito più visitato in Russia; da oltre due anni Nginx è in produzione su questo sito. Igor ha rilasciato il codice sotto licenza BSD-like. Anche se ancora in beta, Nginx è conosciuto per la sua stabilità, ricche funzionalità, semplice configurazione e basso consumo di risorse. "

Tra tutti i web server open source nginx è il più diffuso dopo apache e lighttpd. Attualmente ha il tasso di crescita più alto.

Perchè usare Nginx?

Il motivo principale per utilizzare Nginx è il rapporto prestazioni/risorse: contrariamente ad Apache che apre un nuovo processo per ogni richiesta, Nginx usa un piccolo numero fisso di processi che funzionano in modo asincrono (ad esempio sfruttando epoll su linux). In questo modo l'utilizzo di risorse rimane molto più limitato.

Tra le funzionalità che ci interessano ci sono:
- funzione di virtual host basata sull'IP o nome dell'host
- funzione reverse-proxy (senza cache),
- configurazione semplice e flessibile
- riconfigurazione e aggiornamento senza dover riavviare il demone (e quindi senza perdere connessioni)
- funzionalità per il bilanciamento di carico su più server (load balancing di tipo round-robin) e gestione fault tolerance

Per un panorama completo di tutte le funzionalità questo è il wiki ufficiale.

Installazione e configurazione

Procediamo! Come installare il prodotto (scaricarlo online o utilizzare il pacchetto della propria distribuzione) e configurarlo.

Installazione

E' possibile scaricare e compilare l'ultima versione dal sito ufficiale oppure utilizzare il pacchetto della propria distribuzione.

Ovviamente compilare dai sorgenti permette di avere l'ultima release del prodotto mentre la versione pacchettizzata risulta vantaggiosa dal punto di vista della gestione (oltre ad essere assai più veloce da installare).

Installazione dai sorgenti

Ho seguito le indicazioni di questo sito. La distribuzione utilizzata è la debian (ma vale anche per ubuntu).
Per compilare è necessario installare (apt-get install) le seguenti dipendenze:
- build-essential (ovviamente tutto il necessario per compilare)
- libgcrypt11-dev
- libcpre-dev (perl regular expression library) necessario per utilizzare le espressioni regolari sugli URL
- libssl-dev (libreria necessaria per https)
- zlib1-dev (zlib per utilizzare il formato gzip previsto da http 1.1)
Dopo di questo ho scaricato il pacchetto

wget http://sysoev.ru/nginx/nginx-0.6.32.tar.gz

e l'ho scompattato

tar xvzf nginx-0.6.32.tar.gz

dopo essere entrato nella cartella lanciare

./configure

prendere nota dei vari percorsi (è possibile cambiarli con apposite opzioni del configure)
lanciare

make && make install

 

per compilare ed installare

Installare dai pacchetti della nostra distribuzione

Se la versione pacchettizzata della nostra distribuzione è abbastanza aggiornata è possibile installare tutto con

apt-get install nginx

Oltre ad installare il programma verranno create per noi il file /etc/init.d/nginx per far partire nginx e la cartella /etc/nginx con i file di configurazione. In questo caso c'è un file di configurazione principale nginx.conf, la cartella sites-available con dentro tutti i siti disponibili che devono essere linkati sotto sites-enabled per essere attivi (in modo analogo ad apache).

Una delle funzionalità interessanti di Nginx è proprio la possibilità di controllare il programma mediante i segnali (utilizzando il comando kill). Infatti per ricaricare il file di configurazione o per aggiornare a caldo il programma si usano i segnali utilizzando il pid che si trova in uno dei file di nginx:
term,int -> shutdown rapido
quit -> shutdown
hup -> ricarica configurazione (in caso di problemi utilizza la configurazione precedente)
Sul questo sito c'è un reference completo di tutti i segnali.

A questo punto bisogna configurare nginx come reverse proxy.

Configurazione

Il file di configurazione è abbastanza semplice: è diviso per argomenti raggruppati in parentesi graffe. Ogni argomento contiene una serie di definizioni separate da uno spazio e terminate dal punto e virgola.
A noi interessano le sezioni server: ognuna di queste contiene la configurazione di un server virtuale (virtual host)
quello di default contiene:

server{
    listen 80;
    server_name localhost;
    access_log  /var/log/nginx/localhost.access.log;


    location / {
        root /var/www/nginx-default;
        index index.html index.htm;
    }
}

In questo caso nginx (in ascolto sulla porta 80), per il server localhost, funziona come webserver statico utilizzando i file nella cartellla /var/www/nginx-default.

La configurazione che serve a noi è questa:

server{
    listen 80;
    server_name www.nostrosito.com;
    access_log  /var/log/nginx/nostrosito.access.log;
    rewrite /(.*) /VirtualHostBase/http/www.nostrosito.com:80/plone/VirtualHostRoot/$1 last;
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

L'istruzione rewrite modifica l'url utilizzando l'espressione regolare /(.*) in pratica tutto ciò che nell'url segue il carattere / viene riconosciuto e sostituito con /VirtualHostBase/http/www.nostrosito.com:80/plone/VirtualHostRoot/$1 ($1 corrisponde alla parte riconosciuta racchiusa tra parentesi).
Ad esempio
/pagina1
/(.*)
viene sostituito con
/VirtualHostBase/http/www.nostrosito.com:80/plone/VirtualHostRoot/pagina1

In seguito la location / viene dirottata con l'opzione proxy_pass sul server di plone (in questo caso http://127.0.0.1:8080). In alternativa è possibile dirottare la connessione su un caching proxy server (ad esempio squid o varnish) oppure verso un load balancer.

L'oggetto di zope VirtualHostBase farà in modo che tutti gli url utilizzati da plone punteranno a http://www.nostrosito.com/.

Giusto a titolo di confronto riporto l'analoga configurazione di apache (ricordarsi di abilitare i moduli rewrite e proxy):

RewriteEngine On

RewriteUrl ^/(.*) http://127.0.0.1:8080/VirtualHostBase/http/www.nostrosito.com:80/plone/VirtualHostRoot/$1 [L,F]

 

Alcuni benchmarks

Ecco alcuni test su apache ed nginx che evidenziano le differenti architetture dei due prodotti

Hardware e configurazione del sistema usato per i test

Il test è stato effettuato su questa configurazione:

Intel Pentium Dual  CPU (E2140) a 1.60GHz (dual core). Equipaggiato con 512 MB di ram (di cui 64MB condivisi con la scheda video).


La distribuzione utilizzata è una debian etch con apache versione 2.2.3 e Nginx versione 0.6.32.

Tuning dei web server

Ho configurato i server per servire la stessa pagina statica.

Apache

La configurazione di default di apache è piuttosto conservativa: questo per evitare di far collassare il server se sottoposto ad un numero eccessivo di richieste.
Per effettuare i test ho dovuto quindi modificare alcuni parametri:

MaxKeepAliveRequest 0

La configurazione di default permette un massimo di 100 connessioni keep-alive (0 significa connessioni infinite).
Su debian apache viene configurato in compilazione per l'utilizzo del  motore mod_prefork (un processo per ogni connessione). Ho modificato i seguenti parametri:

ServerLimit 1000
MaxClient 1000

 

in questo modo dovrebbe gestire fino a 1000 connessioni.

Il numero di client gestibile da apache è pari a

maxclient = ram disponibile/ram occupata singolo processo

 

Nginx

Le uniche modifiche su Nginx sono:

worker_processes 2

Con questa voce vengono creati due processi master. In questo modo posso sfruttare i due core del processore.

worker_connection 1024

Con questo parametro vengono configurate il numero massimo di connessioni per ogni processo master.

La formula per calcolare il numero massimo di client è

maxclient = worker_processes * worker_connection

Nella configurazione reverse-proxy si usa una formula un po' diversa:

maxclient = worker_processes * worker_connection / 4

in quanto i browser aprono di default 2 connessioni al server e nginx ne apre altrettante per collegarsi al backend.

 

Modalità di test

Ho utilizzato apache bench per sottoporre i web server ad un certo numero di richieste ed ho raccolto i dati con vmstat.

Apache bench (ab) fa parte del pacchetto apache2-util. E' un semplice tool a riga di comando che esegue per un determinato numero di secondi la richiesta di un url utilizzando un determinato numero di connessioni concorrenti.
Le opzioni utilizzate sono queste:

ab -kc numeroconnessioniconcorrenti -t secondi http://webserver/

Secondo le configurazione di default ab effettua un massimo di 50000 richieste http dopodicchè termina.
Ho utilizzato l'opzione k che prevede connessioni keep-alive in quanto mi interessava mostrare la differente gestione delle connessioni tra i due programmi.

Attenzione: ab crea un certo numero di socket consumando i descrittori di file disponibili nel sistema. Per oltrepassare le 800 richieste concorrenti è stato necessario aumentare il numero dei descrittori con il comando "ulimit -n 2000".

Con vmstat ho raccolto i dati sul sistema in esame.

In sostanza sul pc client ho lanciato ab per 60 secondi con vari livelli di concorrenza.
Sul pc server ho lanciato vmstat 1 60 (output ogni secondo per 60 secondi).

Risultati dei test

Apache ha retto con 200 e 400 richieste concorrenti: da 500 in poi non è riuscito a raggiungere le 20000 risposte (sulle 50000).
Nginx invece ha retto senza errori fino a 1000 richieste concorrenti: oltre le 1000 continua a rispondere a tutte le richieste fallendone qualcuna.
Ad esempio su 1500 richieste concorrenti ha risposto correttamente 49819 volte (su 50000).
Come tempi di risposta tra i due programmi non ci sono evidenti differenze: crescono in modo proporzionale alla concorrenza delle richieste.

Controllando le risorse impiegate emergono dei dati molto interessanti:
Sotto il profilo della cpu emerge grosso modo che Nginx ne usa la metà di Apache.

In questo grafico confronto la percentuale di cpu di apache con 200 e 400 connessioni concorrenti e nginx con 200 e 1000 connessioni. Un aspetto evidente è che il consumo di cpu risulta indipendente dal livello di concorrenza (sarebbe interessante provare ad aumentare i worker_processes di nginx per vedere se le performance aumentano).

 

cpu

Per quanto riguarda la ram si evidenzia la maggior occupazione di apache per singola connessione. Questo porta l'occupazione di ram a salire in modo repentino.

Dal grafico si evince che, su apache con oltre 400 connessioni concorrenti, la memoria libera finisce in fretta e la memoria virtuale non riesce a gestire il flusso di richieste. Questo spiega l'interruzione delle risposte.

 

Free ram

I dati raccolti confermano la differenza tecnologica tra i due prodotti: la creazione di un nuovo processo per ogni nuova connessione porta apache ad occupare eccessive risorse. Per contro Nginx, grazie alla sua struttura asincrona, risulta molto più scalabile.

Conclusioni

Riporto alcuni casi d'uso trovati su internet:

- reverse proxy, load balancer (ad esempio wordpress)

- reverse proxy di apache per servire file statici (vedi qui)
- come imap/pop proxy (fastmail.fm)

In definitiva, a mio parere, l'utilizzo di Nginx può essere una valida alternativa in siti ad alto traffico.