Vous avez donc besoin que votre application soit avertie lorsqu'une session expire dans Redis.
Bien que Redis ne prenne pas en charge cette fonctionnalité, vous pouvez utiliser un certain nombre d'astuces pour l'implémenter.
Mise à jour :à partir de la version 2.8.0, Redis prend en charge cette http://redis.io/topics/notifications
Premièrement, les gens y réfléchissent :c'est encore en discussion, mais cela pourrait être ajouté à une future version de Redis. Consultez les problèmes suivants :
- https://github.com/antirez/redis/issues/83
- https://github.com/antirez/redis/issues/594
Maintenant, voici quelques solutions que vous pouvez utiliser avec les versions actuelles de Redis.
Solution 1 :patcher Redis
En fait, ajouter une simple notification lorsque Redis effectue l'expiration de la clé n'est pas si difficile. Il peut être implémenté en ajoutant 10 lignes au fichier db.c du code source Redis. Voici un exemple :
https://gist.github.com/3258233
Ce court patch poste une clé dans la liste #expired si la clé a expiré et commence par un caractère '@' (choix arbitraire). Il peut facilement être adapté à vos besoins.
Il est alors trivial d'utiliser les commandes EXPIRE ou SETEX pour définir un délai d'expiration pour vos objets de session, et d'écrire un petit démon qui boucle sur BRPOP pour sortir de la liste "#expired", et propager la notification dans votre application.
Un point important est de comprendre comment fonctionne le mécanisme d'expiration dans Redis. Il existe en fait deux chemins différents pour l'expiration, tous deux actifs en même temps :
-
Mécanisme paresseux (passif). L'expiration peut se produire à chaque accès à une clé.
-
Mécanisme actif. Une tâche interne échantillonne régulièrement (au hasard) un certain nombre de clés avec un ensemble d'expiration, en essayant de trouver celles qui expirent.
Notez que le correctif ci-dessus fonctionne correctement avec les deux chemins.
La conséquence est que le délai d'expiration de Redis n'est pas exact. Si toutes les clés ont expiré, mais qu'une seule est sur le point d'expirer et qu'elle n'est pas accessible, la tâche d'expiration active peut prendre plusieurs minutes pour trouver la clé et l'avoir expirée. Si vous avez besoin d'une certaine précision dans la notification, ce n'est pas la voie à suivre.
Solution 2 :simuler l'expiration avec zsets
L'idée ici est de ne pas s'appuyer sur le mécanisme d'expiration de clé Redis, mais de le simuler en utilisant un index supplémentaire plus un démon d'interrogation. Il peut fonctionner avec une version Redis 2.6 non modifiée.
Chaque fois qu'une session est ajoutée à Redis, vous pouvez exécuter :
MULTI
SET <session id> <session content>
ZADD to_be_expired <current timestamp + session timeout> <session id>
EXEC
L'ensemble trié to_be_expired n'est qu'un moyen efficace d'accéder aux premières clés qui doivent expirer. Un démon peut interroger to_be_expired en utilisant le script côté serveur Lua suivant :
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
La commande pour lancer le script serait :
EVAL <script> 1 to_be_expired <current timestamp>
Le démon obtiendra au plus 10 éléments. Pour chacun d'eux, il doit utiliser la commande DEL pour supprimer les sessions, et avertir l'application. Si un élément a été réellement traité (c'est-à-dire que le retour du script Lua n'est pas vide), le démon doit boucler immédiatement, sinon un état d'attente d'une seconde peut être introduit.
Grâce au script Lua, il est possible de lancer plusieurs démons de polling en parallèle (le script garantit qu'une session donnée ne sera traitée qu'une seule fois, puisque les clés sont retirées de to_be_expired par le script Lua lui-même).
Solution 3 :utiliser un minuteur distribué externe
Une autre solution consiste à s'appuyer sur une minuterie distribuée externe. Le système de file d'attente léger de haricot magique est une bonne possibilité pour cela
Chaque fois qu'une session est ajoutée dans le système, l'application publie l'ID de session dans une file d'attente de haricot magique avec un délai correspondant au délai d'expiration de la session. Un démon écoute la file d'attente. Lorsqu'il peut retirer un élément de la file d'attente, cela signifie qu'une session a expiré. Il suffit de nettoyer la session dans Redis et de notifier l'application.