2009-06-15 18 views
43

OK, quindi ho questo raro scenario unico di un sito web PHP bilanciato dal carico. Il problema è che non era bilanciato dal carico. Ora stiamo iniziando a ottenere problemi ...sessioni PHP in un cluster di bilanciamento del carico - come?

Attualmente l'unico problema è con le sessioni PHP. Naturalmente nessuno ha pensato prima a questo problema, quindi la configurazione della sessione PHP è stata lasciata ai suoi valori predefiniti. Quindi entrambi i server hanno il loro piccolo archivio di file di sessione, e guai è l'utente che ottiene la successiva richiesta lanciata all'altro server, perché non ha la sessione che ha creato sul primo.

Ora, ho letto il manuale PHP su come risolvere questa situazione. Lì ho trovato la bella funzione di session_set_save_handler(). (E, per coincidenza, this topic su SO) Neat. Tranne che dovrò chiamare questa funzione in tutte le pagine del sito. E gli sviluppatori di pagine future dovrebbero ricordarsi di chiamarlo tutto il tempo pure. Sembra un po 'goffo, per non parlare probabilmente della violazione di una dozzina di migliori pratiche di codifica. Sarebbe molto più bello se potessi semplicemente capovolgere alcune opzioni di configurazione globale e Voilà - tutte le sessioni vengono memorizzate magicamente in un DB o in una memoria cache o qualcosa del genere.

Qualche idea su come fare questo?


Aggiunto: Per chiarire: mi aspetto che questa sia una situazione standard con una soluzione standard. A proposito, ho un DB MySQL disponibile. Sicuramente ci deve essere un codice pronto all'uso che risolva questo problema? Posso, naturalmente, scrivere la mia sessione di salvataggio e l'opzione auto_prepend evidenziata da Greg sembra promettente, ma sarebbe come reinventare la ruota. : P
Aggiunto 2: Il bilanciamento del carico è basato su DNS. Non sono sicuro di come funzioni, ma suppongo che dovrebbe essere qualcosa come this.
Aggiunto 3: OK, vedo che una soluzione è quella di utilizzare auto_prepend opzione per inserire una chiamata a session_set_save_handler() in tutti gli script e scrivere il mio persister DB, forse gettando in chiamate a memcached per migliorare le prestazioni. Giusto.

C'è anche un modo per evitare di scrivere tutto questo da solo? Come alcuni plugin PHP famosi e ben collaudati?

aggiunto molto, molto più tardi: Questo è il modo in cui sono andato alla fine: How to properly implement a custom session persister in PHP + MySQL?

Inoltre, ho inserito semplicemente il gestore di sessione manualmente in tutte le pagine.

risposta

31

È possibile impostare PHP per gestire le sessioni nel database, in modo che tutti i server condividono stesse informazioni di sessione, come tutti i server utilizzano lo stesso database per questo.

Un buon tutorial può essere found here.

+5

Questo non è il modo corretto. Il problema sono le sessioni PHP, dimenticando i database, stiamo parlando di PHP. Questa soluzione è solo una soluzione. – Daniel

+8

Non sono d'accordo. Memorizzare le sessioni PHP nel database è un'ottima soluzione a questo problema. –

+3

@MattFletcher è una soluzione scadente al problema. dovrebbe essere usata la memoria, come redis, memcached, o ramfs ecc. – r3wt

3

La cosa più semplice da fare è configurare il bilanciamento del carico in modo che invii sempre la stessa sessione allo stesso server.

Se si desidera utilizzare ancora session_set_save_handler, allora forse dare un'occhiata a auto_prepend.

+0

Il bilanciamento del carico è in qualche modo fatto con le voci DNS. Il nome host si risolve in due diversi indirizzi IP e il browser ne sceglie uno a caso. O qualcosa del genere - non conosco davvero i particolari. Ma AFAIK non ha bilanciamento del carico. "Auto_prepend" sembra promettente. –

+0

+1 usa auto_prepend per inserire la funzione session_set_save_handler prima di ogni script – Galen

+2

Sembra che tu abbia un "Round Robin DNS" in movimento - http://en.wikipedia.org/wiki/Round_robin_DNS. Dirò che meno ha detto di questa "soluzione" per bilanciare il carico, meglio è. – Ian

1

Quando abbiamo avuto questa situazione abbiamo implementato del codice che risiede in un'intestazione comune.

In sostanza per ogni pagina controlliamo se conosciamo l'ID di sessione. Se non controlliamo se siamo nella situazione che descrivi, controllando se abbiamo memorizzato i dati di sessione nel DB. In caso contrario, iniziamo una nuova sessione.

Ovviamente questo richiede che tutti i dati rilevanti vengano copiati nel DB, ma se si incapsulano i dati della sessione in una classe separata, allora funziona OK.

6

Non si parla di quale tecnologia si sta utilizzando per il bilanciamento del carico (software, hardware, ecc.); ma in ogni caso, la soluzione al tuo problema è di utilizzare "sessioni adesive" sul bilanciamento del carico.

In sintesi, questo significa che quando arriva la prima richiesta da un "nuovo" visitatore, viene assegnato un server specifico dal cluster: tutte le richieste future per la durata della loro sessione vengono quindi indirizzate a quel server. In pratica ciò significa che le applicazioni scritte per funzionare su un singolo server possono essere scalate in un ambiente bilanciato con zero/poche modifiche al codice.

Se si utilizza un sistema di bilanciamento hardware, ad esempio un dispositivo Radware, le sessioni permanenti vengono configurate come parte dell'installazione del cluster. I dispositivi hardware di solito ti danno un controllo più preciso: quale server a cui è assegnato un nuovo utente (possono controllare lo stato di salute ecc. E scegliere il server più sano/meno utilizzato) e un maggiore controllo su cosa succede quando un server fallisce e cade fuori dal cluster. L'inconveniente dei bilanciatori hardware è il costo, ma ne vale la pena.

Per quanto riguarda i bilanciatori software, si tratta di ciò che si sta utilizzando. Per Apache c'è la proprietà stickysession su mod_proxy - e un sacco di articoli tramite Google per ottenere questo lavoro con la sessione php (for example)


Edit: Da altri commenti inviati dopo la domanda iniziale, suona come la vostra il "bilanciamento" viene effettuato tramite Round Robin DNS, pertanto quanto sopra probabilmente non verrà applicato. Mi asterrò dal commentare ulteriormente e dal dare inizio a una fiammata contro il round robin dns.

+0

Non ho scelto questa soluzione né posso cambiarla. –

1

si potrebbe anche provare a utilizzare memcache come gestore di sessione

1

Se si utilizzano sessioni php, è possibile condividere con NFS la directory/tmp, dove penso che le sessioni siano archiviate, tra tutti i server nel cluster. In questo modo non hai bisogno di un database.

Modificato: È anche possibile utilizzare un servizio esterno come memcachedb (persistente e veloce) e memorizzare le informazioni di sessione nell'indice memcachedb e identificare con un hash del contenuto o addirittura l'ID di sessione.

+0

Questa è la "soluzione rapida" corrente, ma l'amministratore non gli piace. Qualcosa sulla sicurezza e cose del genere, non conosco i particolari. –

+0

Mmm, quindi è possibile utilizzare un servizio esterno come memcachedb utilizzando un hash della chiave come indice per le sessioni. Il servizio memcachedb è molto veloce (in particolare la scrittura) e facile da usare, è possibile utilizzare un set speciale e ridotto delle funzioni memcached da PHP. – Khriz

+2

hai provato id? sembra rischioso e instabile. – knoopx

17

Il modo in cui gestiamo questo è tramite memcached. Tutto ciò che serve sta cambiando il php.ini simile al seguente:

session.save_handler = memcache 
session.save_path = "tcp://path.to.memcached.server:11211" 

Usiamo AWS ElastiCache, in modo che il percorso del server è un dominio, ma sono sicuro che sarebbe stato simile per memcached locale.

Questo metodo non richiede alcuna modifica del codice dell'applicazione.

+4

memcached è una benedizione mista per l'archiviazione delle sessioni. È veloce, facile da configurare ma quando esaurisce la memoria distruggerà le vecchie sessioni, quindi l'archiviazione permanente delle sessioni non funzionerà.Prima di usare questo, si dovrebbe davvero pensare se questa perdita di dati va bene o no per la sua applicazione. –

+1

Maggiori informazioni qui: http://php.net/manual/en/memcached.sessions.php Nota: la maggior parte della documentazione è in realtà nei commenti lì! –

1

Se avete tempo e si vuole ancora controllare più soluzioni, dare un'occhiata a http://redis4you.com/articles.php?id=01 ..

Utilizzando Redis si è fault tolerant. Dal mio punto di vista, potrebbe essere migliore delle soluzioni di memcache per via di questa robustezza.

0

potrebbe essere troppo tardi, ma check this out: http://www.pureftpd.org/project/sharedance

Sharedance è un server ad alte prestazioni per centralizzare chiave/dati effimeri coppie su host remoti, senza il sovraccarico e la complessità di uno SQL Banca dati.

È stato principalmente progettato per condividere cache e sessioni tra un pool di server Web . L'accesso a un server di condivisione è banale tramite una semplice API PHP e è compatibile con le aspettative dei gestori di sessioni PHP 4 e PHP 5.

0

Quando si tratta di gestire la sessione php nel cluster di bilanciamento del carico, è meglio avere sessioni di Sticky Session. Per questo chiedi alla rete di datacenter che sta mantenendo il bilanciamento del carico per abilitare la sessione adesiva. Una volta abilitato, non dovrai preoccuparti delle sessioni alla fine del php

+0

Bene, senza sessioni appiccicose si ottiene anche il failover. :) Tuttavia, la domanda originale presenta una ruga diversa: il bilanciamento del carico è il tipo "DNS round-robin". Quindi le sessioni appiccicose sono fuori questione comunque. : P –

+0

@ Vilx- Abbiamo affrontato lo stesso problema per la sessione in PHP con il servizio di bilanciamento del carico, e questo ha funzionato per noi. L'unica cosa che abbiamo fatto è stata richiesta al nostro datacenter per abilitare la sessione persistente per il dominio configurato e richiedere il routing solo in round-robin – harigorana

Problemi correlati