通过Redisson监听Redis集群的Key过期事件的实现指南
作者:非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过期事件的资料请关注脚本之家其它相关文章!
