当前位置: 首页 > 面试题库 >

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

羊舌旭尧
2023-03-14
问题内容

我想实现一个基于Redis的会话存储。我想将会话数据放入Redis。但是我不知道如何处理会话过期。我可以遍历所有redis密钥(sessionid)并评估上次访问时间和最大空闲时间,因此我需要将所有密钥加载到客户端中,并且可能有1000m会话密钥,并且可能导致非常差的I
/ O表演。
我想让Redis管理过期,但是密钥过期时没有侦听器或回调,因此无法触发HttpSessionListener。有什么建议吗?


问题答案:

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

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

更新:从2.8.0版开始,Redis确实支持以下
http://redis.io/topics/notifications

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

  • https://github.com/antirez/redis/issues/83
  • https://github.com/antirez/redis/issues/594

现在,这是您可以与当前Redis版本一起使用的一些解决方案。

解决方案1:修补Redis

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

https://gist.github.com/3258233

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

然后使用EXPIRE或SETEX命令设置会话对象的过期时间,并编写一个小的守护程序(在BRPOP上循环以从“

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

  • 惰性(被动)机制。过期可能会在每次访问密钥时发生。

  • 主动机制。内部作业会定期(随机)对具有到期设置的多个密钥进行采样,以尝试找到要到期的密钥。

请注意,上述补丁在两个路径下均能正常工作。

结果是Redis的到期时间不准确。如果所有密钥都已到期,但是只有一个即将到期,并且无法访问,则活动的到期作业可能需要几分钟才能找到该密钥并使它到期。如果您需要通知中的某些准确性,则不是要走的路。

解决方案2:使用zset模拟到期

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

每次将会话添加到Redis时,您都可以运行:

MULTI
SET <session id> <session content>
ZADD to_be_expired <current timestamp + session timeout> <session id>
EXEC

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

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

启动脚本的命令为:

EVAL <script> 1 to_be_expired <current timestamp>

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

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

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

另一种解决方案是依靠外部分布式计时器。该轻量级排队系统魔豆是一个很好的可能性

每次在系统中添加会话时,应用程序都会以与会话超时相对应的延迟将会话ID发布到beantalk队列中。守护程序正在监听队列。当它可以使项目出队时,表示会话已过期。它只需要清理Redis中的会话,然后通知应用程序。



 类似资料:
  • 问题内容: 我在我的应用程序中使用Spring安全功能,但是我发现,当会话过期时,所有请求ajax返回页面login.jsp(不重定向,在http响应中,它放置所有html内容)即登录页面我的webapp。我在应用程序中使用了很多ajax请求,目标是返回某些错误代码,例如510,而不是登录页面。 没有invalid-session-url,我试图使invalid-session-url =“”,不

  • 我已经编辑了php配置以保存Redis上的会话。一切正常,但我意识到,有一天已经过去了,通过在redis-cli上运行命令键*,显示了一个巨大的php-session条目列表。我的问题是php是否会在任何时候删除这些键,或者我必须做一些事情来防止这种情况发生。我对此很担心。

  • 我正在使用ActiveMQ对电子邮件进行排队,消费者读取队列并发送电子邮件。 在启动时,我注册一个生产者,并永远缓存它。 有时,当连接关闭时,生产者无法将消息加入队列。 有人能告诉我处理闭门会议的最佳方式吗?我应该重新注册我的制作人吗?还是有办法重开会话?

  • 我知道使用spring boot,您不需要打开和关闭Hibernate会话。 而是为了理解它是如何在内部工作的,它在哪一层打开Hibernate会话,以及何时关闭Hibernate会话。 我创建了一个PoC。我有一个spring boot应用程序,它有两个实体,一个是,另一个是,和之间有一对多的关系。 我有一个两个API,一个是添加记录,另一个是获取所有记录。这些API存在于CustomerEnd

  • 问题内容: 我正在使用HttpClient 4.1.1来测试服务器的REST API。 我可以设法登录似乎正常,但是当我尝试执行其他任何操作时,我都失败了。 我很可能在下一个请求中设置cookie时遇到问题。 这是我目前的代码: 有没有更好的方法来管理HttpClient包中的会话/ cookie设置? 问题答案: 正确的方法是准备一个需要设置的,然后依次传递给每个呼叫。

  • 我有这样的场景,当点击一个按钮时,它打开了一个基于PDF文件的窗口: 我使用的是Gecko驱动程序版本-21.0Firefox版本-61.0.1 Selenium独立服务器-3.13 我无法切换到基于PDF文件的窗口获取错误: 我想用最新的壁虎驱动程序-21.0来处理它