Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

como lidar com a expiração da sessão com base no redis?


Portanto, você precisa que seu aplicativo seja notificado quando uma sessão expirar no Redis.

Embora o Redis não suporte esse recurso, há vários truques que você pode usar para implementá-lo.

Atualização:a partir da versão 2.8.0, o Redis oferece suporte a isso http://redis.io/topics/notifications

Primeiro, as pessoas estão pensando nisso:isso ainda está em discussão, mas pode ser adicionado a uma versão futura do Redis. Veja os seguintes problemas:
  • https://github.com/antirez/redis/issues/83
  • https://github.com/antirez/redis/issues/594

Agora, aqui estão algumas soluções que você pode usar com as versões atuais do Redis.

Solução 1:corrigindo o Redis

Na verdade, adicionar uma notificação simples quando o Redis executa a expiração da chave não é tão difícil. Ele pode ser implementado adicionando 10 linhas ao arquivo db.c do código-fonte do Redis. Aqui está um exemplo:

https://gist.github.com/3258233

Este pequeno patch publica uma chave na lista #expired se a chave expirou e começa com um caractere '@' (escolha arbitrária). Pode ser facilmente adaptado às suas necessidades.

É então trivial usar os comandos EXPIRE ou SETEX para definir um tempo de expiração para seus objetos de sessão e escrever um pequeno daemon que faz um loop no BRPOP para desenfileirar da lista "#expired" e propagar a notificação em seu aplicativo.

Um ponto importante é entender como funciona o mecanismo de expiração no Redis. Na verdade, existem dois caminhos diferentes para expiração, ambos ativos ao mesmo tempo:

  • Mecanismo preguiçoso (passivo). A expiração pode ocorrer cada vez que uma chave é acessada.

  • Mecanismo ativo. Uma tarefa interna regularmente (aleatoriamente) faz a amostragem de várias chaves com expiração definida, tentando localizar as que expiram.

Observe que o patch acima funciona bem com ambos os caminhos.

A consequência é que o tempo de expiração do Redis não é preciso. Se todas as chaves tiverem expiração, mas apenas uma estiver prestes a expirar e não for acessada, o trabalho de expiração ativo poderá levar vários minutos para localizar a chave e expirou. Se você precisa de alguma precisão na notificação, este não é o caminho a seguir.

Solução 2:simulando expiração com zsets

A ideia aqui é não depender do mecanismo de expiração de chave Redis, mas simulá-lo usando um índice adicional mais um daemon de pesquisa. Ele pode funcionar com uma versão Redis 2.6 não modificada.

Cada vez que uma sessão é adicionada ao Redis, você pode executar:
MULTI
SET <session id> <session content>
ZADD to_be_expired <current timestamp + session timeout> <session id>
EXEC

O conjunto classificado to_be_expired é apenas uma maneira eficiente de acessar as primeiras chaves que devem expirar. Um daemon pode pesquisar em to_be_expired usando o seguinte script do lado do servidor 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

O comando para iniciar o script seria:
EVAL <script> 1 to_be_expired <current timestamp>

O daemon receberá no máximo 10 itens. Para cada um deles, deve-se usar o comando DEL para remover as sessões e notificar o aplicativo. Se um item foi realmente processado (ou seja, o retorno do script Lua não está vazio), o daemon deve fazer um loop imediatamente, caso contrário, um estado de espera de 1 segundo pode ser introduzido.

Graças ao script Lua, é possível lançar vários daemons de polling em paralelo (o script garante que uma determinada sessão será processada apenas uma vez, pois as chaves são removidas de to_be_expired pelo próprio script Lua).

Solução 3:use um temporizador distribuído externo

Outra solução é contar com um temporizador distribuído externo. O sistema de filas leves de pé de feijão é uma boa possibilidade para isso

Cada vez que uma sessão é adicionada ao sistema, o aplicativo envia o ID da sessão para uma fila de beanstalk com um atraso correspondente ao tempo limite da sessão. Um daemon está escutando a fila. Quando ele pode desenfileirar um item, significa que uma sessão expirou. Basta limpar a sessão no Redis e notificar o aplicativo.