前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探索SpringSession与Redis的完美结合:解决分布式会话管理难题

探索SpringSession与Redis的完美结合:解决分布式会话管理难题

作者头像
烟雨平生
发布2023-10-25 12:36:56
4900
发布2023-10-25 12:36:56
举报
文章被收录于专栏:数字化之路数字化之路
  • 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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档