Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redisson监听Redis Key过期事件

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

作者:非ban必选

在分布式系统中,监听 Redis 键过期事件是实现缓存失效、订单超时取消等功能的常用方案,本文将详细介绍如何通过 Redisson 高效监听 Redis 集群的 Key 过期事件,需要的朋友可以参考下

引言

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

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

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

1. 修改配置文件

# 开启键过期事件通知(E表示键事件,x表示过期事件)
notify-keyspace-events Ex

2. 生效配置

# 连接任意集群节点执行
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);
    }
}

关键配置说明:

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
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. 如何保证事件处理的可靠性?

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

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

您可能感兴趣的文章:
阅读全文