book - redis tutorial
Redis, expiración de sesión y búsqueda inversa (2)
En la versión actual de la rama de Redis (2.6), no puede recibir notificaciones cuando los elementos han caducado. Probablemente cambiará con las próximas versiones.
Mientras tanto, para cumplir con sus requisitos, debe implementar manualmente el soporte de notificación de vencimiento. Así que tienes:
session:<sessionid> -> a hash storing your session data - one of the field is <userid>
user:<userid> -> a set of <sessionid>
Debe eliminar sessionid del conjunto de usuarios cuando caduque la sesión. Así que puedes mantener un conjunto ordenado adicional cuya puntuación es una marca de tiempo.
Cuando creas la sesión 10 para el usuario 100:
MULTI
HMSET session:10 userid:100 ... other session data ...
SADD user:100 10
ZADD to_be_expired <current timestamp + session timeout> 10
EXEC
Luego, debe crear un demonio que sondee el zset para identificar la sesión que caduca (ZRANGEBYSCORE). Para cada sesión caducada, debe mantener la estructura de datos:
- saca la sesión del zset (ZREMRANGEBYRANK)
- recuperar usuario de sesión (HMGET)
- borrar sesión (DEL)
- eliminar sesión del conjunto de ID de usuario (SREM)
La principal dificultad es asegurarse de que no haya condiciones de carrera cuando el daemon sondea y procesa los elementos. Vea mi respuesta a esta pregunta para ver cómo se puede implementar:
Actualmente estoy construyendo una aplicación web y me gustaría usar Redis para almacenar sesiones. Al iniciar sesión, la sesión se inserta en Redis con el ID de usuario correspondiente y la caducidad se establece en 15 minutos. Ahora me gustaría implementar la búsqueda inversa de sesiones (obtener sesiones con un ID de usuario determinado). El problema aquí es que, como no puedo buscar en el espacio de teclas de Redis, cómo implementar esto. Una forma sería tener un conjunto redis para cada ID de usuario, que contenga todos los identificadores de sesión. Pero como Redis no permite la caducidad de un elemento en un conjunto, y las sesiones están configuradas para caducar, habría un montón de ID de sesión inexistentes en los conjuntos.
¿Cuál sería la mejor manera de eliminar los identificadores de los conjuntos al vencimiento de la clave? O, ¿hay una mejor manera de lograr lo que quiero (búsqueda inversa)?
En las versiones más recientes de Redis (2.8.0 y superiores), se admiten las notificaciones de espacios clave para eventos expired
. Es decir, cuando una clave con un TTL expira, este evento se activa.
Esto es a lo que debe suscribirse:
''__keyevent@0__:expired''
Entonces, suscribirse a este evento le permite tener un índice único para todas las sesiones y puede eliminar la clave del índice cuando la clave caduque.
Ejemplo:
Utilice un conjunto ordenado como un índice secundario con el uid como el peso:
ZADD "idx-session-uid" <uid> <sessionkey>
Buscar claves de sesión para un usuario específico con:
ZRANGEBYSCORE "idx-session-uid" <uid> <uid>
Cuando se borra o caduca una sesión hacemos:
ZREM "idx-session-uid" <sessionkey>