首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何处理基于redis的会话过期?

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

Stack Overflow用户
提问于 2012-08-05 00:02:57
回答 1查看 17.9K关注 0票数 14

我想实现一个基于Redis的会话存储。我想把会话数据放到Redis中。但是我不知道如何处理会话过期。我可以遍历所有redis密钥(sessionid),并评估最后访问时间和最大空闲时间,因此我需要将所有密钥加载到客户端,并且可能有1000m会话密钥,可能会导致非常差的I/O性能。

我想让Redis来管理过期,但是密钥过期时没有监听器,也没有回调,所以不可能触发HttpSessionListener。有什么建议吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-08-05 18:12:52

因此,您需要在Redis中的会话到期时通知您的应用程序。

虽然Redis不支持此功能,但您可以使用许多技巧来实现它。

Redis更新:从2.8.0版本开始,不支持此

首先,人们正在考虑它:这仍在讨论中,但它可能会添加到未来版本的Redis中。请参阅以下问题:

现在,这里有一些你可以在当前的Redis版本中使用的解决方案。

解决方案1:修补Redis

实际上,在Redis执行密钥过期时添加一个简单的通知并不难。在Redis源码的db.c文件中添加10行即可实现。下面是一个示例:

https://gist.github.com/3258233

如果密钥已过期并以'@‘字符开头(任意选择),则此简短补丁将密钥发布到#expired列表。它可以很容易地适应您的需求。

然后就可以使用EXPIRE或SETEX命令来设置会话对象的过期时间,并编写一个在BRPOP上循环的小守护进程,以便从"#expired“列表中出队,并在应用程序中传播通知。

重要的一点是理解Redis中的过期机制是如何工作的。实际上有两种不同的过期路径,这两种路径都同时处于活动状态:

  • 惰性(被动)机制。该期满可以在每次密钥是accessed.
  • Active机制时发生。内部作业定期(随机)对设置了过期时间的多个密钥进行采样,试图找到要过期的密钥。

请注意,上面的补丁在两个路径上都可以很好地工作。

结果是Redis的过期时间不准确。如果所有密钥都已过期,但只有一个密钥即将过期,并且未被访问,则活动的过期作业可能需要几分钟才能找到密钥并使其过期。如果你需要在通知中保持一定的准确性,这不是你应该做的。

解决方案2:使用zsets模拟过期

这里的想法是不依赖于Redis密钥过期机制,而是通过使用额外的索引加上轮询守护进程来模拟它。它可以与未修改的Redis 2.6版本一起工作。

每次在Redis中添加一个会话,您都可以运行:

代码语言:javascript
复制
MULTI
SET <session id> <session content>
ZADD to_be_expired <current timestamp + session timeout> <session id>
EXEC

to_be_expired排序集只是访问应该过期的第一个密钥的一种有效方法。守护进程可以使用以下Lua服务器端脚本在to_be_expired上轮询:

代码语言:javascript
复制
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

启动脚本的命令为:

代码语言:javascript
复制
EVAL <script> 1 to_be_expired <current timestamp>

守护进程将获得最多10个项目。对于它们中的每一个,它都必须使用DEL命令删除会话,并通知应用程序。如果实际处理了一个项目(即Lua脚本的返回值不为空),守护进程应该立即循环,否则会出现1秒的等待状态。

多亏了Lua脚本,可以并行启动多个轮询守护进程(该脚本保证给定的会话只处理一次,因为Lua脚本本身会从to_be_expired中删除密钥)。

解决方案3:使用外部分布式计时器

另一种解决方案是依靠外部分布式定时器。为此,beanstalk lightweight queuing system是一个很好的选择

每次在系统中添加会话时,应用程序都会将会话ID发送到具有与会话超时对应的延迟的beanstalk队列。守护进程正在监听队列。当它可以将项出队时,就意味着会话已过期。它只需要清理Redis中的会话,并通知应用程序。

票数 41
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11810020

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档