22

I'm currently bulding a web app and would like to use Redis to store sessions. At login, the session is inserted into Redis with a corresponding user id, and expiration set at 15 minutes. I would now like to implement reverse look-up for sessions (get sessions with a certain user id). The problem here is, since I can't search the Redis keyspace, how to implement this. One way would be to have a redis set for each userId, containing all session ids. But since Redis doesn't allow expiration of an item in a set, and sessions are set to expire, there would be a ton of inexistent session ids in the sets.

What would be the best way to remove ids from sets on key expiration? Or, is there a better way of accomplishing what I want (reverse look-up)?

4

2 回答 2

25

Redis (2.6)的当前版本分支上,您无法在项目过期时收到通知。它可能会随着下一个版本而改变。

同时,为了支持您的需求,您需要手动实现过期通知支持。所以你有了:

session:<sessionid> -> a hash storing your session data - one of the field is <userid>
user:<userid> -> a set of <sessionid>

sessionid会话到期时,您需要从用户集中删除。因此,您可以维护一个附加的排序集,其分数是一个时间戳。

当您为用户 100 创建会话 10 时:

MULTI
HMSET session:10 userid:100 ... other session data ...
SADD user:100 10
ZADD to_be_expired <current timestamp + session timeout> 10
EXEC

然后,您需要构建一个守护进程,它将轮询 zset 以识别会话到期(ZRANGEBYSCORE)。对于每个过期的会话,它必须维护数据结构:

  • 将会话从 zset ( ZREMRANGEBYRANK)中弹出
  • 检索会话用户 ID ( HMGET)
  • 删除会话 ( DEL)
  • 从用户 ID 集中删除会话 ( SREM)

主要困难是确保在守护进程轮询和处理项目时没有竞争条件。请参阅我对这个问题的回答,了解如何实施:

如何处理基于redis的会话过期?

于 2013-05-25T08:27:32.700 回答
5

在 Redis 的更新版本(2.8.0 及更高版本)中,支持事件的键空间通知。expired即,当具有 TTL 的密钥过期时,将触发此事件。

这是要订阅的内容:

'__keyevent@0__:expired'

因此,订阅此事件允许您为所有会话拥有一个索引,并且您可以在键过期时从索引中删除键。

例子:

使用排序集作为二级索引,以 uid 作为权重:

ZADD "idx-session-uid" <uid> <sessionkey>

使用以下命令搜索特定用户的会话密钥:

ZRANGEBYSCORE "idx-session-uid" <uid> <uid>

当会话被删除或过期时,我们会:

ZREM "idx-session-uid" <sessionkey>
于 2018-05-24T16:52:55.497 回答