2012-08-04 11 views
13

Desidero implementare i resoconti basati su sessioni di archiviazione, ho inserito i dati di sessione in redis. Ma non so come gestire la scadenza della sessione.Posso eseguire il ciclo di tutte le chiavi redis (sessionid) ed evaolare i dati lastaccess e maxidle, quindi ho bisogno di caricare tutte le chiavi nel client, e ci sono forse 1000m di chiavi di sessione e potrebbe portare prestazioni di I/O del pool molto elevate.
I wanto let redis gestisce la scadenza, ma non ci sono listener o callback quando la chiave scade, quindi è impossibile tiger HttpSessionListener. qualche consiglio?come gestire la sessione scaduta basando redis?

+0

Non in Redis, ma si consiglia di dare un'occhiata a come si fa in Tarantool: https://github.com/mailru/tntlua/blob/master/expirationd.lua In poche parole, in Tarantool voi può eseguire i propri script Lua nel database e impostare le proprie politiche di scadenza in loro. Non sono necessari demoni esterni. – Kostja

risposta

33

Quindi è necessario che l'applicazione venga notificata quando una sessione scade in Redis.

Sebbene Redis non supporti questa funzione, è possibile utilizzare una serie di trucchi per implementarla.

Aggiornamento: A partire dalla versione 2.8.0, Redis non supportano questa http://redis.io/topics/notifications

In primo luogo, la gente pensa a questo proposito: questo è ancora in discussione, ma potrebbe essere aggiunto a una futura versione di Redis. Vedere i seguenti problemi:

Ora, qui alcune soluzioni che è possibile utilizzare con le versioni attuali Redis.

Soluzione 1: l'applicazione di patch Redis

In realtà, l'aggiunta di una semplice notifica quando Redis esegue scadenza della chiave non è così difficile. Può essere implementato aggiungendo 10 righe al file db.c del codice sorgente Redis. Ecco un esempio:

https://gist.github.com/3258233

Questo breve post di patch una chiave per la lista #expired se la chiave è scaduto e inizia con un carattere '@' (scelta arbitraria). Può essere facilmente adattato alle tue esigenze.

È quindi banale utilizzare i comandi EXPIRE o SETEX per impostare un tempo di scadenza per gli oggetti di sessione e scrivere un piccolo daemon che si sposta su BRPOP per disconnettersi dall'elenco "#expired" e propagare la notifica nel proprio applicazione.

Un punto importante è capire come funziona il meccanismo di scadenza in Redis. In realtà ci sono due percorsi diversi per scadenza, attivi contemporaneamente:

  • pigro (passiva) meccanismo. La scadenza può verificarsi ogni volta che si accede a una chiave.

  • Meccanismo attivo. Un lavoro interno regolarmente (a caso) campiona un numero di chiavi con scadenza impostata, cercando di trovare quelle che scadono.

Si noti che la patch di cui sopra funziona bene con entrambi i percorsi.

La conseguenza è che il tempo di scadenza di Redis non è preciso.Se tutte le chiavi hanno scadenza, ma solo una sta per scadere e non è accessibile, il processo di scadenza attivo può richiedere diversi minuti per trovare la chiave e scaduta. Se hai bisogno di precisione nella notifica, questa non è la strada da percorrere.

Soluzione 2: simulando scadenza con zsets

L'idea è di non fare affidamento sul meccanismo di scadenza della chiave Redis, ma simulare utilizzando un indice aggiuntivo e un demone di polling. Può funzionare con una versione Redis 2.6 non modificata.

Ogni volta che una sessione viene aggiunto a Redis, è possibile eseguire:

MULTI 
SET <session id> <session content> 
ZADD to_be_expired <current timestamp + session timeout> <session id> 
EXEC 

L'insieme ordinato to_be_expired è solo un modo efficiente per accedere alle prime chiavi che dovrebbero essere scaduti. Un demone può interrogare sulla to_be_expired utilizzando il seguente script lato server Lua:

local res = redis.call('ZRANGEBYSCORE',KEYS[1], 0, ARGV[1], 'LIMIT', 0, 10) 
if #res > 0 then 
    redis.call('ZREMRANGEBYRANK', KEYS[1], 0, #res-1) 
    return res 
else 
    return false 
end 

Il comando per avviare lo script sarebbe:

EVAL <script> 1 to_be_expired <current timestamp> 

Il demone otterrà al massimo 10 elementi. Per ognuno di essi, deve utilizzare il comando DEL per rimuovere le sessioni e notificare l'applicazione. Se un articolo è stato effettivamente processato (cioè il ritorno dello script Lua non è vuoto), il daemon dovrebbe eseguire il ciclo immediatamente, altrimenti può essere introdotto uno stato di attesa di 1 secondo.

Grazie allo script Lua, è possibile lanciare più demoni di polling in parallelo (lo script garantisce che una determinata sessione verrà elaborata una sola volta, poiché le chiavi vengono rimosse da to_be_expired dallo script stesso Lua).

Soluzione 3: utilizzare un timer distribuito esterna

Un'altra soluzione è di affidarsi a un timer distribuita esterna. beanstalk lightweight queuing system è una buona possibilità per questo

Ogni volta che viene aggiunta una sessione nel sistema, l'applicazione registra l'ID di sessione su una coda di beanstalk con un ritardo corrispondente al timeout della sessione. Un demone sta ascoltando la coda. Quando può deselezionare un oggetto, significa che una sessione è scaduta. Deve solo pulire la sessione in Redis e notificare l'applicazione.

+0

Sorprendente risposta - grazie mille! Puoi chiarire questa frase: "il daemon dovrebbe eseguire il ciclo immediatamente, altrimenti è possibile introdurre uno stato di attesa di 1 secondo". Cosa significa looping in questo contesto - e perché/dove viene introdotta questa attesa di 1 secondo? –

+0

I demoni sono programmi residenti che a volte si svegliano per svolgere attività nel sistema. Poiché sono costantemente in esecuzione, la maggior parte del codice è racchiusa in un ciclo principale. Ora un demone ha bisogno anche di uno stato di attesa, per evitare di prendere il 100% della CPU durante il ciclo. Non esiste alcun comando di blocco associato a un set z con Redis (a differenza di BLPOP/BRPOP per la lista), quindi deve essere simulato dal polling e dalla sospensione se non viene restituito nulla. –

+2

Questo è già implementato in redis. Questi problemi sono chiusi. Sarebbe bello se qualcuno aggiorni questa risposta. –

Problemi correlati