通过Redisson监听Redis集群的Key过期事件的实现指南

 更新时间:2025年11月09日 14:09:44   作者:非ban必选  
在分布式系统中,监听 Redis 键过期事件是实现缓存失效、订单超时取消等功能的常用方案,本文将详细介绍如何通过 Redisson 高效监听 Redis 集群的 Key 过期事件,需要的朋友可以参考下

引言

在分布式系统中,监听 Redis 键过期事件是实现缓存失效、订单超时取消等功能的常用方案。本文将详细介绍如何通过 Redisson 高效监听 Redis 集群的 Key 过期事件,包含环境配置、代码实现及最佳实践,适用于生产环境落地。

一、前置条件:开启 Redis 集群的键过期通知

Redis 默认关闭键事件通知,需在所有集群节点的配置文件(redis.conf)中开启过期事件监听,确保事件能被正确触发:

1. 修改配置文件

# 开启键过期事件通知(E表示键事件,x表示过期事件)
notify-keyspace-events Ex
  • 配置说明:notify-keyspace-events参数用于指定监听的事件类型,Ex组合表示仅监听键过期事件(减少不必要的事件推送,提升性能)。

2. 生效配置

  • 若 Redis 已启动,可通过命令临时生效(重启后失效):
# 连接任意集群节点执行
redis-cli -h 192.168.1.1 -p 6379 config set notify-keyspace-events Ex
  • 生产环境建议修改配置文件后重启集群,确保配置持久化。

二、引入 Redisson 依赖

Redisson 提供了对 Redis 集群的原生支持,通过 Spring Boot Starter 可快速集成:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.52.0</version>
</dependency>

三、配置 Redisson 连接 Redis 集群

Redisson 通过Config类配置集群连接,需指定节点地址、认证信息及连接池参数,确保高可用:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class RedissonClusterConfig {
 
    @Bean(destroyMethod = "shutdown") // 容器销毁时关闭客户端,释放资源
    public RedissonClient redissonClient() {
        Config config = new Config();
        
        // 配置Redis集群(至少填写一个主节点地址,Redisson会自动发现其他节点)
        config.useClusterServers()
              .addNodeAddress(
                  "redis://192.168.1.1:6379",
                  "redis://192.168.1.2:6379",
                  "redis://192.168.1.3:6379"
              )
              // 认证配置
              .setPassword("your-redis-password") // 若集群启用密码认证
              .setUsername("default") // Redis 6.0+支持用户名认证,默认留空
              
              // 连接池配置(根据业务压力调整)
              .setMasterConnectionPoolSize(32) // 主节点连接池大小
              .setSlaveConnectionPoolSize(16)  // 从节点连接池大小
              .setIdleConnectionTimeout(30000) // 连接空闲超时(毫秒)
              
              // 集群特性配置
              .setScanInterval(2000) // 集群节点健康检查间隔(毫秒)
              .setReadMode(ReadMode.SLAVE) // 读操作路由到从节点,减轻主节点压力
              .setRetryAttempts(3) // 命令执行失败重试次数
              .setRetryInterval(1000); // 重试间隔(毫秒)
 
        return Redisson.create(config);
    }
}

关键配置说明:

  • destroyMethod = "shutdown":确保 Spring 容器销毁时,Redisson 客户端优雅关闭,避免连接泄漏。
  • ReadMode.SLAVE:非过期事件的读操作可路由到从节点,适合读多写少场景。
  • 连接池大小:根据并发量调整,建议主节点连接池不超过 64(避免 Redis 连接数过载)。
  • 配置文件配置如下
spring:
  datasource:
    druid:
      password: xxxxxxx
      url: jdbc:mysql://127.0.0.1:3306/service?useUnicode=true&allowMultiQueries=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
      username: root
  redis:
    redisson:
      file: classpath:redisson-clu.yaml
  • redisson-clu.yaml
clusterServersConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  failedSlaveReconnectionInterval: 3000
  failedSlaveCheckInterval: 60000
  password: xxxxxxx
  subscriptionsPerConnection: 5
  clientName: null
  loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  slaveConnectionMinimumIdleSize: 24
  slaveConnectionPoolSize: 64
  masterConnectionMinimumIdleSize: 24
  masterConnectionPoolSize: 64
  readMode: "SLAVE"
  subscriptionMode: "SLAVE"
  nodeAddresses:
  - "redis://127.0.0.1:6380"
  - "redis://127.0.0.1:6381"
  - "redis://127.0.0.1:6382"
  - "redis://127.0.0.1:6383"
  - "redis://127.0.0.1:6384"
  - "redis://127.0.0.1:6385"
  scanInterval: 1000
  pingConnectionInterval: 0
  keepAlive: false
  tcpNoDelay: false
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.JsonJacksonCodec> {}
transportMode: "NIO"

四、实现 Key 过期事件监听器

Redisson 提供两种订阅方式:RTopic(指定数据库)和RPatternTopic(通配符订阅),需结合StringCodec解析事件消息(Redis 过期事件的消息为键名字符串)。

方式 1:监听指定数据库的过期事件(精确订阅)

适用于仅关注特定数据库(如 DB 7)的场景,减少无关事件干扰:

package com.yh.service.config;
 
import org.redisson.api.RPatternTopic;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.redisson.api.listener.PatternMessageListener;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import javax.annotation.PostConstruct;
 
@Component
public class RedisKeyExpireListener {
 
    @Autowired
    private RedissonClient redissonClient;
    
 
    @PostConstruct
    public void listenExpireEvent1() {
        // 仅监听 DB 7 的键过期事件
        RTopic topic = redissonClient.getTopic("__keyevent@7__:expired", StringCodec.INSTANCE);
 
        // 注册监听器
        topic.addListener(String.class, new MessageListener<String>() {
            @Override
            public void onMessage(CharSequence channel, String msg) {
                //输出过期的key 值
                System.out.println(msg);
            }
        });
 
    }
}

效果如下

方式 2:监听所有数据库的过期事件(通配符订阅)

适用于需要监听集群中所有数据库过期事件的场景,通过通配符*匹配所有数据库:

package com.yh.service.config;
 
import org.redisson.api.RPatternTopic;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.redisson.api.listener.PatternMessageListener;
import org.redisson.client.codec.StringCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import javax.annotation.PostConstruct;
 
@Component
public class RedisKeyExpireListener {
 
    @Autowired
    private RedissonClient redissonClient;
 
 
//    @PostConstruct
//    public void listenExpireEvent1() {
//        // 仅监听 DB 7 的键过期事件
//        RTopic topic = redissonClient.getTopic("__keyevent@7__:expired", StringCodec.INSTANCE);
//        // 注册监听器
//        topic.addListener(String.class, new MessageListener<String>() {
//            @Override
//            public void onMessage(CharSequence channel, String msg) {
//                //输出过期的key 值
//                System.out.println(msg);
//            }
//        });
//    }
 
 
    @PostConstruct  // 初始化时订阅事件
    public void listenExpireEvent() {
        // 订阅所有数据库的键过期事件(__keyevent@*__:expired)
        RPatternTopic topic = redissonClient.getPatternTopic("__keyevent@*__:expired",StringCodec.INSTANCE);
 
        // 添加消息监听器
        topic.addListener(String.class,new PatternMessageListener<String>() {
            @Override
            public void onMessage(CharSequence pattern, CharSequence channel, String msg) {
                //输出过期的key 值
                System.out.println(msg);
            }
        });
    }
}

效果如下

五、关键技术细节与最佳实践

1. 为什么必须使用 StringCodec?

Redis 的过期事件消息内容是原始键名字符串(如order:123),而 Redisson 默认使用JsonJacksonCodec(JSON 解析)。若不指定StringCodec,会导致 JSON 解析错误(如JsonParseException: Unrecognized token 'order'),因此必须显式指定字符串编码器。

2. 如何保证事件处理的可靠性?

  • 异步处理:监听器的onMessage方法运行在 Redisson 的 Netty IO 线程中,需通过线程池异步执行业务逻辑,避免阻塞事件监听。
  • 防止丢失:Redis 事件通知是 “fire and forget” 模式,监听器宕机期间的事件会丢失。关键业务需结合:
    • 定时任务兜底(如每 10 分钟扫描超时订单);
    • 事件持久化(监听到事件后先存入 Redis Stream/Kafka,再消费处理)。
  • 幂等性设计:同一事件可能因集群主从切换被重复推送,需确保业务逻辑幂等(如处理前检查订单状态)。

3. 性能与集群适配注意事项

  • 集群事件路由:Redis 集群中,键过期事件会在键所在的节点触发,Redisson 会自动订阅所有节点的事件,无需额外配置。
  • 连接池隔离:业务线程池需与 Redisson 的内部线程池隔离,避免业务阻塞影响 Redis 连接。
  • 事件过滤:通过键名前缀(如order:)过滤无关事件,减少无效处理。
  • 监控告警:添加 metrics 监控(如事件总数、处理成功率),结合告警机制及时发现异常。

以上就是通过Redisson监听Redis集群的Key过期事件的实现指南的详细内容,更多关于Redisson监听Redis Key过期事件的资料请关注脚本之家其它相关文章!

相关文章

  • Redis中渐进式遍历Scan命令的使用

    Redis中渐进式遍历Scan命令的使用

    在Redis中,一般都会禁用keys 这种命令,因为它会遍历整个数据库,会严重影响redis的性能,本文就来介绍一下Redis中渐进式遍历Scan命令的使用,感兴趣的可以了解一下
    2023-11-11
  • 关于redis状态监控和性能调优详解

    关于redis状态监控和性能调优详解

    Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富。有字符串,链表、哈希、集合和有序集合5种。下面这篇文章主要给大家介绍了关于redis状态监控和性能调优的相关资料,需要的朋友可以参考下。
    2017-09-09
  • 使用拦截器+Redis实现接口幂思路详解

    使用拦截器+Redis实现接口幂思路详解

    这篇文章主要介绍了使用拦截器+Redis实现接口幂等,接口幂等有很多种实现方式,拦截器/AOP+Redis,拦截器/AOP+本地缓存等等,本文讲解一下通过拦截器+Redis实现幂等的方式,需要的朋友可以参考下
    2023-08-08
  • 分布式使用Redis实现数据库对象自增主键ID

    分布式使用Redis实现数据库对象自增主键ID

    本文介绍在分布式项目中使用Redis生成对象的自增主键ID,通过Redis的INCR等命令实现计数器功能,具有一定的参考价值,感兴趣的可以了解一下
    2024-12-12
  • Redis数据库安全详解

    Redis数据库安全详解

    这篇文章主要为大家介绍了Redis数据库安全详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Redis之Jedis中zset类型使用方式

    Redis之Jedis中zset类型使用方式

    zadd的score为double类型,添加多个元素需用map;zrange返回List,zrangeWithScore返回List<Tuple>,zcard和zrem返回Long,zscore返回Double包装类需注意null,zrank返回Long包装类
    2025-09-09
  • Redis 实现“附近的人”功能

    Redis 实现“附近的人”功能

    Redis基于geohash和有序集合提供了地理位置相关功能。这篇文章主要介绍了Redis 实现“附近的人”功能,需要的朋友可以参考下
    2019-11-11
  • Redis 多规则限流和防重复提交方案实现小结

    Redis 多规则限流和防重复提交方案实现小结

    本文主要介绍了Redis 多规则限流和防重复提交方案实现小结,包括使用String结构和Zset结构来记录用户IP的访问次数,具有一定的参考价值,感兴趣的可以了解一下
    2025-02-02
  • mac下redis安装、设置、启动停止方法详解

    mac下redis安装、设置、启动停止方法详解

    这篇文章主要介绍了mac下redis安装、设置、启动停止方法详解,需要的朋友可以参考下
    2020-02-02
  • Redis分布式锁的超时机制实现的方法示例

    Redis分布式锁的超时机制实现的方法示例

    本文介绍了Redis分布式锁中超时机制的关键作用,通过设置锁的过期时间防止客户端崩溃导致的死锁问题,具有一定的参考价值,感兴趣的可以了解一下
    2025-10-10

最新评论