引言
上期我们讲述了如何用springboot+springsession整合redis的操作,实现分布式session共享,这期我们主要探究在redis中存储的session数据。
redis中存储的设计结构
在调用http://localhost:8080/session/createSession后,我们可以看到redis中多了session数据,每个session存储了三条信息 如下图
对上述键值数据结构做一个简单的分析
类型 | 键 | 数据结构 | TTL |
---|---|---|---|
1 | spring:session:sessions:expires:fe77fcfc-6235-4dad-a7df-b6589fb71b18 | Hash | 35分钟 |
2 | spring:session:expirations:1681786620000 | Set | 30 分钟 |
3 | spring:session:sessions:expires:fe77fcfc-6235-4dad-a7df-b6589fb71b18 | String | 30分钟 |
第一种类型键
用来存储session数据的详细信息,主要包括Session最近的访问时间、过期时间间隔、创建时间、attributes(像我们添加的sname,name都会存储在这里)
这个key的过期时间为Session的最大过期时间 + 5分钟。如果默认的最大过期时间为30分钟,则这个key的过期时间为35分钟。
第二种类型键
spring:session:expirations 为set结构, 存储1681788060000指定时间点过期的 所有spring:session:sessions:expires 键值 如下图
第三种类型键
用来表示Session在Redis中的过期,这个key-val不存储任何有用数据【存储一个空值】,只是表示Session过期而设置。具体作用便是在自身过期后触发 Redis 的 keyspace notifications,keyspace notifications 只会告诉我们哪个键过期了,不会告诉我们内容是什么。所以Session 过期后监听器可能访问不了 Session 的具体内容。
思考
在Redis中过期key的策略有两种:
- 当访问时发现其过期,此时才删除,触发事件【惰性删除】
- Redis后台逐步查找过期的键【定时删除】
通过springsession的使用,我们可以发现两个问题
内存和CPU销毁大
当访问时发现其过期,才会产生过期事件,这就意味着,如果一直没有访问的话,过期事件一直不会触发,session也就一直不会销毁。也就是说无法保证key的过期时间抵达后立即生成过期事件,因为前端请求过来时,优先拿服务器的tomcat缓存,redis中的数据可能一直没有被访问。
即使expire到了,也还是没被及时访问,没法触发过期事件。
用户状态不一致
解耦 Session 的存储和过期,并且使得 server 获取到过期通知后可以访问到 Session 真实的值。
对于用户来说,第三种类型键过期后,意味着登录失效,而对于服务端而言,真正的过期其实是 A第一种类型键过期,这中间会有 5 分钟的误差。
总结
Spring Session 是一套严谨的设计方案,为了监听session的创建、过期等事件,引入了定时器和很多辅助的键值对,带来了更多的内存消耗。所以,在用户量很大的情况下,需要多方考虑下相关问题。所以,我们选择JWT代替springsession作为SSO单点登录的认证方案。下期,我们将进一步考虑JWT的相关问题,更好的实现单点登录。