squid come reverse proxy

Squid è un prodotto eccellente per fare da web cache; sia che si voglia alleggerire il carico sulla connessione, sia che si voglia fare del filtraggio a livello applicativo sia che si abbia la necessità di fare del monitoraggio molto dettagliato dell’uso del web su di una rete, la flessibilità di questo applicativo permette di intervenire praticamente su ogni aspetto del protocollo http e non solo.

Segnalo fin da subito che squid, come tutti i prodotti di web cache, richiede un’ attenzione particolare alla configurazione, in particolare per l’aspetto dei permessi; si corre il rischio, infatti, di mettere su internet un server proxy che può essere usato da terzi per mascherare le proprie attività.

Oggi voglio mostrare come configurare squid per usarlo come reverse-proxy. Si parla di proxy quando la cache viene messa davanti ai client e risolve al posto di questi le chiamate su internet. Si parla di reverse-proxy quando il server viene posto davanti ai web server e raccoglie al posto dei server web le chiamate dei client.

La ragione base per cui si fa questo è migliorare le prestazioni incidendo il meno possibile sui costi. I server cache infatti mantengono in memoria e/o su disco le risposte alle richieste più frequenti dei client e rispondono direttamente senza convolgere i server web; infatti  sono in genere in grado si rispondere ad un numero di richieste molto più alto di un server web che sempre più spesso deve essere configurato per gestire elaborazioni pesanti.

Squid è un prodotto molto consolidato ed è presente oramai sui tutte le distribuzioni linux. Per istallarlo quindi in genere la cosa più semplice è ricorrere ai tool della propria distribuzione. Su Debian/Ubuntu:

sudo aptitude update
sudo aptitude search squid
sudo aptitude install squid

La configurazione di default di squid è molto ben fatta e contiene così tanti commenti da essere quasi completamente autoesplicativa; merita un’esame se si vuole utilizzare questo prodotto. Nel nostro caso però la costruiremo da zero. Come risulta dalla documentazione ufficiale ci sono più possibilità per la configurazione in modalità Reverse Proxy; ne analizzeremo una di uso ragionevolmente generale.

http_port 80 accel defaultsite=[server name] vhost

cache_peer [IP sorgente 1] parent 80 0 no-query originserver name=RevPro1
acl web1 dstdomain [accelerated domains list 1]

cache_peer [IP sorgente 2] parent 80 0 no-query originserver name=RevPro2
acl web2 dstdomain [accelerated domains list 2]

http_access allow web1
http_access allow web2
cache_peer_access RevPro1 allow web1
cache_peer_access RevPro2 allow web2

cache_dir diskd /var/cache/squid3 1000 32 32 Q1=64 Q2=72
cache_mem 1024 MB

cache_replacement_policy heap LFUDA
memory_replacement_policy heap GDSF
cache_swap_low  90
cache_swap_high 95

Vediamo ora questa configurazione in maggiore dettaglio:

http_port 80 accel defaultsite=[server name] vhost

In questo modo si dice a squid che lavorerà in modalità reverse-proxy e con che tipo di configurazione. Defaultsite conviene valorizarlo con il nome del server web, quali sono i siti di cui si fa reverse proxy viene specificato più avanti. Vhost specifica che la discriminante per la scelta del server di origine sarà il dominio.

cache_peer [IP sorgente 1] parent 80 0 no-query originserver name=RevPro1

Definiamo qui un server web di cui fare reverse proxy e assegniamo un nome a questa definizione (RevPro1).

acl web1 dstdomain [accelerated domains list 1]

Definiamo una lista di siti web (separati da spazi) di cui si vuole fare reverse proxy e le assegnamo un nome (web1).

cache_peer [IP sorgente 2] parent 80 0 no-query originserver name=RevPro2
acl web2 dstdomain [accelerated domains list 2]

Ripeto per un secondo server origin e una seconda lista di siti.

http_access allow web1
http_access allow web2

dico a squid che deve rispondere alle richieste (dei client) relative alle due liste di siti web1 e web2.

cache_peer_access RevPro1 allow web1
cache_peer_access RevPro2 allow web2

Associo le origin alle liste dei siti supponendo che un dato server web di origine serve alcuni dei siti mentre l’altro serve gli altri.

cache_dir diskd /var/cache/squid3 1000 32 32 Q1=64 Q2=72
cache_mem 1024 MB

cache_replacement_policy heap LFUDA
memory_replacement_policy heap GDSF
cache_swap_low  90
cache_swap_high 95

Infine queste righe configurano la cache.

Come quasi sempre su squid si definiscono degli oggetti per definire attività da permettere o vietare; si definiscono delle acl per definire il “chi” ed infine si associano questi due tipi di informazione in righe dove si definisce chi può fare cosa.

Come sempre prima di mettere in produzione un server con squid è bene leggerne la documentazione ufficiale.

Memcached – 2

Come già accennato nel precedente post, memcached è un daemon piuttosto semplice da configurare e istallare.

Sui sistemi Debian e derivati memcached può essere istallato con

sudo aptitude install memcached

altrimenti si può ricorrere ai sistemi di pacchettizzazione delle altre architetture o direttamente ai sorgenti rilasciati dagli sviluppatori.

Se si istalla da pacchetto debian a valle dell’istallazione verrà lanciato un daemon che, come risulta da ps aux, sarà:

/usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1

La configurazione completa sarà invece in

/etc/memcached.conf

Analizziamo i parametri di avvio

  • -l: l’ip su cui il demone è in ascolto
  • -p: la porta TCP su cui il demone è in ascolto
  • -m: la quantità di memoria (in MB) che viene assegnata al demone memcached

e non visibili perché con impostazioni di default (ma riportati sul file di configurazione)

  • -d: memcached viene lanciato in modalità demone e quindi rilascia il controllo all’ambiente che lo ha avviato
  • logfile: path del file di log
  • -c: numero massimo di connessioni contemporanee accettate
  • -M: ritorna errore nel caso non ci sia memoria disponibile
  • -v: incremento del livello di dettaglio nei log
  • -vv: ulteriore incremento del livello di dettaglio nei log

I più imprtanti per il tooning sono ovviamente -m, -c e -M. Nel determinare il primo bisogna tener conto che se l’uso di memcached fa si che il server debba appoggiarsi sullo swap l’effetto complessivo sarà con ogni probabilità quello di peggiorare le prestazioni.

Vale la pena spendere due parole su -M; di default memcached quando non ha più spazio disponibile sovrascrive i valori più vecchi e meno utilizzati. Questo viene indicato come evictions nei report e nella documentazione. Se questo sia accettabile o no dipende da considerazione sull’applicazione che si sta realizzando ma è in genere molto ragionevole per della cache. -M permette di cambiare questo comportamento nel caso dovesse essere necessario.

Per connettersi ad un server memcached è possibile utilizzare un semplice telnet:

telnet localhost 11211

Una volta connessi si possono in teoria eseguire tutte le operazioni; ad esempio salvare una variabile

set pluto 123 0 3
o

dove viene detto di salvare nella variabile pluto il valore o. 123 è un numero arbitrario usato nel protocollo di comunicazione, 0 il tempo di expire del valore (in questo caso infinito) e 3 la dimensione dei dati che verranno inviati.

Si può poi rileggere lo stesso valore con un

get pluto

Attenzione che anche un solo spazio in più fa fallire l’esecuzione del comando.

Questo uso con telnet è paragonabile all’invio della posta con lo stesso strumento ma rimane utile per test e troubleshooting. Qualsiasi uso applicativo deve passare attraverso un’apposita libreria in un qualche linguaggio (php, perl…). Oltretutto a questa libreria sono completamente demandate le funzionalità necessarie per l’uso in cluster.

Il telnet inoltre permette di accedere a ben quattro report molto dettagliati sullo stato interno del daemon:

stats
stats items
stats slabs
stats sizes

Questi quattro comandi sono alla base di report più ad alto livello. Decisamente più maneggevole è ad esempio memcache-top. Questo permette di avere un’istantanea molto comprensibile  dello stato di un pool e dell’efficacia dell’uso che se ne fa:

memcache-top --commands --instance=serv1:port1[,serv2:port2...]

il report sarà qualche cosa come:

memcache-top v0.5       (default port: 11211, color: on, refresh: 3 seconds)

INSTANCE                USAGE   HIT %   CONN    TIME    EVICT   READ    WRITE
serv1:port1             90%     80%     800     0.6ms   20      10G     20G    
serv2:port2             90%     80%     700     0.5ms   10      15G     30G  
...

AVERAGE:                90%     80%     750     0.5ms   15      12.5G   25G  

TOTAL:                  2GB            1500     11.0ms  30      25G     50G    
(ctrl-c to quit.)

Questo report, se non specificato diversamente, viene rigenerato ogni 3s e si riferisce a questo intervallo temporale.

Memcached – 1

Sui sistemi che devono fornire contenuti web dinamici la cache diventa rapidamente un aspetto cruciale al crescere del traffico; su web infatti si possono raggiungere frequenze di accessi ai dati veramente notevoli. Per fortuna, anche se questo è sempre meno vero, c’è una fortissima sproporzione tra gli accessi in lettura e quelli in scrittura e questo permette notevoli semplificazioni nelle soluzione di questo problema.

Di fatto il modo migliore per gestire la massa degli accessi in lettura è l’utilizzo di un qualche sistema di cache. Cache che dovrà essere quanto possibile veloce e semplice. Memcached nasce proprio per questo scopo: permette di riservare su un server un’area di memoria, renderla accessibile via TCP e di salvare su memoria dei valori recuperabili successivamente sulla base di una chiave.

Per rimanere semplice e veloce, memcached mantiene i dati solo in memoria e non li scrive su disco, ne consegue che ogni volta che viene riavviato perde tutti i propri dati. Questo però è un compromesso assolutamente ragionevole per della cache.

Supponiamo ora di dover gestire un sito ad alto traffico e di renderci conto che il nostro database sta divenendo un collo di bottiglia per il nostro sistema. Decidiamo quindi di introdurre memcached e di riuscire in questo modo sia a migliorare le prestazioni del sito sia a ridurre notevolmete gli accessi al database. Nei mesi successivi il traffico sul nostro sito potrà quindi crescere ancora. Si è venuto a creare in questo modo un problema piuttosto insidioso: se il daemon memcached si dovesse riavviare, perderemmo la nostra cache e ci troveremmo con un database non più sufficiente a supportare il nostro sito: sarebbe quindi molto difficile far ripartire il sistema nel suo insieme.

In pratica, se si vogliono sfruttare veramente i vantaggi di memcached bisogna distribuire la cache su diversi server (tutti i server apache ad esempio) in modo tale che al riavvio di un demone memcached si perderebbe solo una parte della cache e il sovraccarico sui database sarebbe quindi contenuto.

I cluster di server memcached sono peculiari in quanto ogni server è un’ entità a se che si preoccupa solamente di immagazzinare e restituire i dati dalla propria memoria e non ha conoscenza del fatto di essere parte di un pool. La logica della gestione del pool è demandata completamente ai client.

Ogni client suddivide la cache in tante parti sulla base della conoscenza deila lista dei server del pool e si andrà a poi a connettere sul server corretto per il salvataggio o il recupero dei dati. L’algoritmo utilizzato per questa operazione è piuttosto interessante e sarà argomento di un altro post.

Un altro problema che si può presentare con questi sistemi deriva dal fatto che su molti siti web ci sono pagine molto accedute e pagine a basso traffico: su un portale probabilmente gran parte degli accessi saranno sulla homepage. Oggetti della cache che vengono utilizzati in queste pagine saranno quindi particolarmente critici e la perdita di uno di questi potrebbe essere un problema anche se percentualmente gran parte della cache è comunque disponibile.

Come detto gà più volte il daemon è piuttosto semplice e semplice è anche la sua configurazioni. La configurazione si riduce di fatto a scegliere:

    • la memoria da riservare
    • il numero massimo di connessioni accettabili
    • se salvare dei log su file