1、session在redis里面的存储结构2
在上一章讲spring session存储到redis的时候,在redis里面看到每一个session存储都会生成三条记录,记录格式如下:
这就很麻烦了,为啥不能一一对应,做彼此的天使呢,搞的一对三,很影响风化啊。到底是道德的沦丧还是人性的扭曲,让我们走进redis,看下具体的数据内容:
第一个k-v存储这个Session的id,是一个Set类型的Redis数据结构。这个key中的最后的1570550340000值是一个时间戳,根据这个Session过期时刻滚动至下一分钟而计算得出。里面的值是这样的
第二个k-v用来表示Session在Redis中的过期,是个String类型,这个k-v不存储任何有用数据,只是表示Session过期而设置。这个key在Redis中的过期时间即为Session的过期时间间隔
第三个k-v用来存储Session的详细信息,是hash类型,包括Session的创建时间、过期时间间隔、最近的访问时间、attributes等等。这个k的过期时间为Session的最大过期时间 + 5分钟。如果默认的最大过期时间为30分钟,则这个k的过期时间为35分钟
说到这里,会有个灵魂的拷问,就一个session的存储,为啥要搞三条记录?这里要提一下HttpSession的接口规范了。
session虽然也是一条数据,但是和普通的数据还是有不同的,我们去查httpsession的javadoc可以看到,session的添加和移除都是可以触发事件的。
触发的前提是对象实现了HttpSessionBindingListener接口,然后我们再看下HttpSessionBindingListener的部分
里面通过HttpSessionBindingEvent来通知session的attribute变化
这一套下来是不是很熟悉,这就是一个典型的监听器模型,也是消息机制的主要表现方式,在spring session通过redis实现分布式的session时,就是通过redis的消息机制来实现标准的session变动通知的,在了解具体的做法先,让我们先看下redis的消息通知功能。
2、啥!redis支持消息的发布订阅?
Redis从2.8.0版本后,推出 Keyspace Notifications 特性。Keyspace Notifications 允许客户端可以以 订阅/发布(Sub/Pub)模式,接收那些对数据库中的键和值有影响的操作事件。这些操作事件具体来说,就是 del , expire , set , rpop等啦。
redis默认不会开启keyspace notifications,因为开启后会对cpu有消耗,所以开启需要额外配置redis.conf文件
############################# EVENT NOTIFICATION ##############################
# Redis can notify Pub/Sub clients about events happening in the key space.
# This feature is documented at http://redis.io/topics/notifications
#
# For instance if keyspace events notification is enabled, and a client
# performs a DEL operation on key "foo" stored in the Database 0, two
# messages will be published via Pub/Sub:
#
# PUBLISH __keyspace@0__:foo del
# PUBLISH __keyevent@0__:del foo
#
# It is possible to select the events that Redis will notify among a set
# of classes. Every class is identified by a single character:
#
# K Keyspace events, published with __keyspace@<db>__ prefix.
# E Keyevent events, published with __keyevent@<db>__ prefix.
# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
# $ String commands
# l List commands
# s Set commands
# h Hash commands
# z Sorted set commands
# x Expired events (events generated every time a key expires)
# e Evicted events (events generated when a key is evicted for maxmemory)
# A Alias for g$lshzxe, so that the "AKE" string means all the events.
#
# The "notify-keyspace-events" takes as argument a string that is composed
# of zero or multiple characters. The empty string means that notifications
# are disabled.
#
# Example: to enable list and generic events, from the point of view of the
# event name, use:
#
# notify-keyspace-events Elg
#
# Example 2: to get the stream of the expired keys subscribing to channel
# name __keyevent@0__:expired use:
#
# notify-keyspace-events Ex
#
# By default all notifications are disabled because most users don't need
# this feature and the feature has some overhead. Note that if you don't
# specify at least one of K or E, no events will be delivered.
notify-keyspace-events "Ex"
关键就是最下一句,Ex的意思可以看上面的注释。启动后只要我们订阅一个特定的channel,该channel下面的数据变化我们就能收到通知了。
改好配置,重启redis,就能够开启消息通知了。
Redis中带有过期的key有两种方式:
- 当访问时发现其过期
- Redis后台逐步查找过期键
问题时访问时发现过期可能会在很久以后,所以怎么才能在key过期的时候就知道呢?
spring-session中有个定时任务,每个整分钟都会查询相应的spring:session:expirations:整分钟的时间戳中的过期SessionId,然后再访问一次这个sessionId,即spring:session:sessions:expires:SessionId,以便能够让Redis及时的产生key过期事件——即Session过期事件。而这个定时任务的时间时可以配置的,配置的参数就时上一章结尾说的cleanupCron
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware,
SchedulingConfigurer {
static final String DEFAULT_CLEANUP_CRON = "0 * * * * *";
private String cleanupCron = DEFAULT_CLEANUP_CRON;
默认就是一分钟清理一次过期的缓存,可以根据自己的需求做更改。
3、总结
- spring session存到redis的每个session数据会有三条记录,一条存储session自身的信息,另外两条存储session过期的信息
- redis可以开启Keyspace Notifications服务,开启后redis的数据出现变动会有通知消息
- spring session可以配置定时任务扫描存到redis的session数据中关于过期信息的两条,定时任务的配置在cleanupCron里面
我这里其实讲的不是很详细,关于spring session方面的细节,大家可以看这一系列的文章,讲的很好,但看的挺累。
来源:oschina
链接:https://my.oschina.net/u/173343/blog/3104545