Distribuzione delle sessioni in PHP in caso di load balancing su più server

Preview:

DESCRIPTION

La distribuzione delle sessioni è un problema che riguarda la scalabilità dei siti web su più server, in particolare per PHP che di norma salva le sessioni su file system del singolo server. In questo talk vedremo alcune strategie di risoluzione del problema (load balancing mirato, accentramento delle sessioni) e ci soffermeremo su una personale soluzione che prevede delle sessioni distribuite su più macchine contemporaneamente creando un’architettura a maglia attraverso l’uso di memcache

Citation preview

Distribuzione delle sessioni in PHP

diGianluca GIMIGLIANO

gimigliano@tin.it

Perché le sessioni?

• Perché il protocollo HTTP è statelessness, ossia non è in grado di veicolare informazioni su eventuali scelte pregresse quindi:– Ogni richiesta del client fa storia a sé e non ha

memoria del passato– Non è possibile associare delle variabili di stato

ad un determinato client

Utilizzo tipico delle sessioni

• Tenere memoria dell’avvenuta autenticazione in un’area riservata

• Mantenere la traccia di scelte effettuate dal navigatore in pagine diverse del sito (es. carrelli)

Come PHP gestisce le sessioni

Quando un client si connette per la prima volta,

il motore delle sessioni del PHP genera un id univoco e crea un file nel quale verranno salvate le “variabili di sessione” e che ha per nome quello stesso id. Insieme alla risposta al al client viene inviato un “cookie di sessione” che ha per valore quell’id.

In questo modo, ogni volta che un client presenterà una richiesta con quel cookie, il PHP saprà in quale file sono contenute la variabili relative a quella sessione ripristinandole

Funzionamento della sessione

GET index.php?scelta=x HTTP/1.1………

a1b2c3d…scelta=x

HTTP 200 OKSet-cookie: SESSID=a1b2c3d..………

GET index.php?scelta2=y HTTP/1.1Cookie: SESSID=a1b2c3d..………

a1b2c3d…scelta=xscelta2=y

Scalare un sito su più server

All’aumentare delle richieste un solo server (virtuale o fisico che sia) può non essere più sufficiente e nasce quindi la necessità di mettere più macchine in batteria.La scelta di quale macchina risponderà ad una determinata richiesta viene fatta da un’apposita apparecchiatura di rete: il “bilanciatore” che garantisce la distribuzione delle richieste secondo politiche definite dall’utente (es. equa distribuzione del carico su tutte le macchine).

Generalmente una macchina bilanciata

• Non è tenuta a sapere di esserlo• E’ configurata esattamente come tutte le

altre• Produce risposte che, sia nel protocollo che

nel contenuto, sono indistinguibili dalle risposte generate da un’altra macchina bilanciata

Il problema delle sessioni con bilanciamento

• Poiché il cookie viene generato da una delle macchine bilanciate ed il file con le variabili si trova su di essa, quando il bilanciatore andrà a instradare una richiesta con il cookie di sessione su un’altra macchina questa non avrà a disposizione memoria del passato della sessione.

• Tale memoria tornerà “misteriosamente” disponibile quando le richieste torneranno sulla macchina che ha generato inizialmente la sessione.

Problema del bilanciatore

GET index.php?scelta=x HTTP/1.1………

a1b2c3d…scelta=x

a1b2c3d…scelta2=y

HTTP 200 OKSet-cookie: SESSID=a1b2c3d..………

GET index.php?scelta2=y HTTP/1.1Cookie: SESSID=a1b2c3d..………

Possibile soluzione 1

• Bilanciamento mirato– Il bilanciatore entra nel merito del protocollo,

riconosce la presenza del cookie di sessione nella risposta del server, e da quel momento tutte le richieste con quel cookie verranno assegnate a quel server

Problema del bilanciatore

GET index.php?scelta=x HTTP/1.1………

a1b2c3d…scelta=xscelta2=y

HTTP 200 OKSet-cookie: SESSID=a1b2c3d..………

GET index.php?scelta2=y HTTP/1.1Cookie: SESSID=a1b2c3d..………

A

BA) “SESSID=a1b2c3d..”

Vantaggi

• Non necessita di modifiche sia negli applicativi che nelle configurazioni dei server

• Veloce, la tabella con le assegnazioni dei cookie ai server è gestita in RAM dal bilanciatore con SW integrato nel firmware

Svantaggi

• Occorre programmare il bilanciatore• Applicazioni diverse potrebbero usare cookie di

sessione con nome diverso ed il bilanciatore deve tenerne conto

• Il bilanciatore non può sapere il peso ed il numero di transazioni che genererà un client a cui assegna una macchina quindi il carico potrebbe risultare paradossalmente sbilanciato (specie se l’algoritmo di distribuzione è pesato per difformità nelle prestazioni delle macchine)

Possibile soluzione 2

• Concentrazione dei dati– I dati di sessione vengono accentrati in un unico

storage condiviso che può essere file sharing, DB, memcache

Esempio di sessioni accentrate

GET index.php?scelta=x HTTP/1.1………

a1b2c3d…scelta=xscelta2=y

HTTP 200 OKSet-cookie: SESSID=a1b2c3d..………

GET index.php?scelta2=y HTTP/1.1Cookie: SESSID=a1b2c3d..………

Vantaggi e svantaggi

• Dipendono dal tipo di storage

File sharing

• Vantaggi– Di facile utilizzazione, basta cambiare la direttiva session.save_path del PHP.ini impostando il percorso della cartella condivisa

– Non prevede nessuna modifica al codice degli script• Svantaggi

– Sicuramente dal punto di vista prestazionale non garantisce risultati eccellenti a meno di investire in apparecchiature dedicate (e costose)

DB

• Vantaggi– Permette di monitorare in tempo reale lo stato delle varie

sessioni tramite SQL– Prestazioni elevate

• Svantaggi– Occorre introdurre codice PHP per la gestione della sessione

(vedremo poi come) che eventualmente si può includere in modo trasparente impostando il parametro auto_prepend_file del PHP.ini

– Se il DB è lo stesso usato per i dati delle applicazioni occorre però verificarne la capacità sopportare entrambi i carichi di lavoro

Memcache

• Vantaggi– Decisamente più veloce di tutti in quanto è un

servizio di RAM condivisa– Non occorre introdurre codice PHP, basta

modificare i parametri del PHP.ini es:[Session]session.save_handler = memcachesession.save_path= "tcp://storage:11211"

• Svantaggi– Le sessioni non hanno un lock di scrittura … ….ma non è detto che sia uno svantaggio

Allora, abbiamo una soluzione?

• Teoricamente Si, ma in realtà tutte le soluzioni proposte hanno una debolezza architetturale:– Se lo storage smette di funzionare nessuna

sessione funziona più e quindi niente più login o carrelli

Possibile soluzione 3

Innanzitutto cambiamo un pochino le classiche caratteristiche di una macchina bilanciata:Non è tenuta a sapere di esserloSa di esserlo e conosce gli IP di tutte le altre macchine bilanciate

Produce risposte che, sia nel protocollo che nel contenuto, sono indistinguibili dalle risposte generate da un’altra macchina bilanciata

Il valore del cookie di sessione è in grado di veicolare informazioni sulla macchina che ha generato la sessione

E’ configurata esattamente come tutte le altre

I presupposti

• Installare una memcache su ogni macchina che fungerà da storage per le sessioni di quel singolo server

• Ad ogni server è assegnata una lettera • Ogni macchina conosce le lettere di tutte le altre

ed è in grado di ricavare l’IP da una data lettera• L’Id di sessione generato da ogni server inizia

sempre con la lettera associata a quella macchina

L’idea

• Quando un server riceve una richiesta per la prima volta genera una sessione nella memcache locale facendo iniziare il cookie di sessione con la propria lettera

• Ogni volta che un server riceve una richiesta con cookie di sessione estrae la prima lettera e, se è la propria usa la sessione locale, altrimenti si connetterà alla memcache del server che ha generato quella sessione

Esempio sessioni distribuite

GET index.php?scelta=x HTTP/1.1………

a1b2c3d…scelta=xscelta2=y

HTTP 200 OKSet-cookie: SESSID=a1b2c3d..………

GET index.php?scelta2=y HTTP/1.1Cookie: SESSID=a1b2c3d..………

A

B

Vantaggi

• Robustezza, tra i server si genera una connettività a “maglia”, in questo modo se un server cade tutti gli altre continuano ad operare salvo il ripristino delle sessioni dei client ”orfani”

• Velocità, derivante dall’uso di memcache

Svantaggi

• Occorre introdurre codice PHP per la gestione della sessione, ma come detto, con la direttiva auto_prepend si può fare in modo trasparente

Ulteriori migliorie

• Fare in modo che il dialogo tra i server avvenga su una rete diversa rispetto a quella sulla quale viaggia il traffico web (ma questa è una regola d’oro per tutte le soluzioni proposte)

• Mettere le memcache su server diversi da quelli che fanno da webserver, in questo modo la lettera si riferirà ad una batteria di server memcache

Batteria di webserver e memcache server

GET index.php?scelta=x HTTP/1.1………

a1b2c3d…scelta=xscelta2=y

HTTP 200 OKSet-cookie: SESSID=a1b2c3d..………

GET index.php?scelta2=y HTTP/1.1Cookie: SESSID=a1b2c3d..………

A

B

Come costruire un gestore di sessioni

• Attraverso la funzione session_set_save_handler è possibile sostituire le operazioni native con quelle personalizzate che vengono generate sugli eventi:– Open: Apertura sella sessione (prima fase di session_start)– Read: Lettura dei dati di sessione dallo storage (seconda fase di

session_start)– Write: Scrittura dei dati nello storage (prima fase di

session_write_close o termine dello script)– Close: Chiusura della sessione (seconda fase di session_write_close

o termine dello script)– Destroy: Distruzione dei dati della sessione (session_destroy)– GC: Pulizia delle sessioni scadute eventualmente invocata durante il

session_start

Una generica classe astratta di gestione sessioni

L’implementazione I° parte

L’implementazione II° parte

Un esempio pratico