- Redis的notify-keyspace-events简介
- Redis过期的特点
- SpringSession基于keyspace-events做了什么
- Spring-Session中Sesssion事件机制探密
- 思考:这样设计是为了解决什么问题
- 小结
什么是Redis的notify-keyspace-events
Redis 2.8版本开始加入了Keyspace notifications功能,它可以监听指定的key,当该key被修改、过期或被删除时,可以发送通知给订阅者。
这个功能提供了一种类似于触发器(trigger)的机制,使得应用程序能够对Redis中的key的变化做出相应的反应。
Redis的notify-keyspace-events是一个配置项,用于配置键空间通知(keyspace notifications)的事件类型。键空间通知是Redis提供的一种机制,用于在某些事件发生时通知客户端。通过配置notify-keyspace-events参数,可以指定要通知的事件类型。
notify-keyspace-events参数的值可以是以下几种组合: K:键空间通知,即键的操作事件,如键的过期、删除等。 E:键事件通知,即键的操作事件,如键的过期、删除等。 g:通用命令通知,即通用命令的操作事件,如DEL、EXPIRE等。 $:字符串命令通知,即字符串命令的操作事件,如SET、GET等。 l:列表命令通知,即列表命令的操作事件,如LPUSH、LPOP等。 s:集合命令通知,即集合命令的操作事件,如SADD、SREM等。 h:哈希命令通知,即哈希命令的操作事件,如HSET、HGET等。 z:有序集合命令通知,即有序集合命令的操作事件,如ZADD、ZREM等。 x:过期事件通知,即键过期时的事件。
通过配置notify-keyspace-events参数,可以选择要通知的事件类型,以便在该事件发生时及时通知相关的客户端。
开启的办法示例:
方法1:更改redis的配置文件redis.conf
方法2:使用redis的config命令
代码语言:javascript复制#监听redis过期引发的删除事件
redis-cli config set notify-keyspace-events Egx
想知道SpringSession使用哪种方式开启,见文末
Redis过期的特点
Redis过期是指为一个键设置一个过期时间,当到达过期时间后,redis客户端就查不到这个key,但这个key并不一定会被删除。
Redis的卖点是快,是高性能,因此只承诺key过期后就不返回给客户端,不承诺key过期后就立即删除。 具体实现上,Redis采用惰性删除和定期删除相结合的策略来删除过期key。 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。 定期删除:Redis默认每秒进行10次过期扫描,过期扫描不会遍历过期字典中所有的key,而是采用了一种简单的贪心算法来尝试删除尽量多的过期key,同时也尽量少的占用Redis服务器的cpu资源,因此算法还增加了扫描时间的上限,默认不会超过25ms。
SpringSession基于keyspace-events做了什么
SpringSession是基于Spring和Redis的会话管理解决方案。 为了实现会话的高可用性和分布式特性,SpringSession基于Redis的notify-keyspace-events功能对key过期和删除事件预留了扩展。 具体来说,SpringSession在启动时会监听Redis的Egx事件,当有新的会话创建或者已有会话过期时,SpringSession会自动更新会话信息,确保用户始终处于登录状态。
Spring-Session中Sesssion事件机制探密
以spring-session-data-redis 2.5.6为例:
代码语言:javascript复制 <dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.5.6</version>
</dependency>
代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableRedisHttpSession {
代码语言:javascript复制 @Bean
public RedisMessageListenerContainer springSessionRedisMessageListenerContainer(
RedisIndexedSessionRepository sessionRepository) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(this.redisConnectionFactory);
if (this.redisTaskExecutor != null) {
container.setTaskExecutor(this.redisTaskExecutor);
}
if (this.redisSubscriptionExecutor != null) {
container.setSubscriptionExecutor(this.redisSubscriptionExecutor);
}
container.addMessageListener(sessionRepository,
Arrays.asList(new ChannelTopic(sessionRepository.getSessionDeletedChannel()),
new ChannelTopic(sessionRepository.getSessionExpiredChannel())));
container.addMessageListener(sessionRepository,
Collections.singletonList(new PatternTopic(sessionRepository.getSessionCreatedChannelPrefix() "*")));
return container;
}
Spring Session启动了redis的事件监听:container.addMessageListener
可以看到,常用的Session事件共三个:
Session事件的抽象
Session Event最顶层是ApplicationEvent,即Spring上下文事件对象。由此可以看出Spring-Session的事件机制是基于Spring上下文事件实现。 Session事件的类图如下所示:
可以基于Spring上下文事件共三个: Session创建事件: SessionCreatedEvent Session删除事件: SessionDeletedEvent Session过期事件: SessionExpiredEvent
Session事件的生命周期如下所示:
上图展示了Spring-Session事件的交互图: 1、事件源来自于Redis键空间通知; 2、在spring-data-redis中的MessageListener监听Redis事件源,这是基于Redis的Pub/Sub; 3、然后通过MessageListener中的逻辑将其传播至Spring应用上下文发布者,由发布者再次发布事件; 4、如果在Spring上下文中存在相关事件的监听器Listener即可监听到相应的Session事件。
SessionCreatedEvent事件
Pub基于Redis的Session创建事件
代码语言:javascript复制 @Override
public void save(RedisSession session) {
session.save();
if (session.isNew) {
String sessionCreatedKey = getSessionCreatedChannel(session.getId());
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
session.isNew = false;
}
}
org.springframework.session.data.redis.RedisIndexedSessionRepository#save
Sub基于Redis的Session创建事件
然后,Pub基于Spring上下文的事件
SessionDeletedEvent和SessionExpiredEvent
这两个事件的事件源来自Redis的Keyspace notifications功能
SpringSession开启Redis的Egx事件监听是通过下面这个类实现的: org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration#configureRedisAction
默认使用ConfigureNotifyKeyspaceEventsAction来开启Egx监听
如何开启Redis Egx监听
this.configure.configure(connection)开启Redis Egx监听
绑定Redis Egx的Listener
Pub基于Spring上下文的事件 org.springframework.session.data.redis.RedisIndexedSessionRepository#onMessage
有没有发现RedisIndexedSessionRepository类是spring-session-data-redis的核心?
思考:这样设计是为了解决什么问题
通过使用Redis的notify-keyspace-events功能,SpringSession可以实现对用户会话的实时监控和管理。这样设计的主要目的是为了解决以下问题:
- 高可用性:通过将会话数据存储在Redis中,可以实现会话的高可用性。即使某个节点出现故障,其他节点仍然可以正常提供服务。
- 分布式特性:SpringSession支持多个应用实例共享同一个Redis实例,从而实现会话的分布式管理。这样,用户在一个应用中的会话信息可以在其他应用中同步,提高了用户体验。
- 自动续签:当用户在应用之间切换时,SpringSession可以自动处理会话的续签,确保用户始终处于登录状态。
小结
本文介绍了Redis的notify-keyspace-events配置选项及其作用,以及Redis过期的特点。接着,我们探讨了SpringSession如何利用Redis的notify-keyspace-events功能实现高可用分布式会话管理。 最后,我们分析了这样设计的目的,即解决高可用性、分布式特性和自动续签等问题。
参考
https://www.cnblogs.com/lxyit/p/9719542.html
https://redis.io/docs/manual/keyspace-notifications/
Spring Session中session的事件监听 https://www.jianshu.com/p/f9b40a563df4
Spring事件机制 ApplicationEventPublisher https://blog.csdn.net/weixin_37672801/article/details/128803430