监听Redis中key过期事件

本文介绍了如何利用Redis的键空间通知功能监听Key过期事件,以实现实时处理订单超时取消等业务需求。通过配置notify-keyspace-events为Ex,配合Spring Data Redis的发布订阅功能,可以实现Java应用中的键过期事件监控。

在工作中偶尔会遇到这样一个场景:用户下单之后,若30分钟内未完成支付,则取消订单。

做过电商业务的同学,尤其是做统一下单业务的同学一般都会接触过这个场景的需求,一般的处理方式是将订单数据存储到数据库中(MySQL之类的),然后由一个定时Job不断的去扫描符合条件的订单,修改订单状态为已取消。当然这只是其中一个处理办法,我们还可以使用到延时队列来处理。

那么如果我们使用Redis是否可以实现这一功能?我们知道在使用Redis的过程中,大多是由客户端主动的去操作服务端,比如set、del、get、expire等操作。而当一个key过期被删除的时候,由服务端主动的去通知客户端,这个要怎么做?

之前在一个项目中,是自己写了一个定时Job不断是去轮询要监听的某些key,然后如果发现Redis中不存在要get的key,则执行一段业务逻辑,我们的扫描频率取决于Job的执行频率,所以并不能保证key在过期时被立即监听到,如果n秒执行一次,则key最大可能会在2n-1秒之后被执行,会有一定的延迟,那么我们能否让Redis主动的在缓存失效的时候通知我们呢?

解析

由服务端主动通知客户端,那么就是需要通过一个事件来触发某项通知,事件通过Redis的订阅和发布功能来进行分发,我们查看Redis的配置文件中有一个EVENT NOTIFICATION配置,也名键空间通知
在这里插入图片描述
注释上说:Redis可以通知发布/订阅客户端关于键空间中发生的事件,如果Redis开启了键空间事件通知,且客户端订阅了某些键的事件,则在相应的键发生变动时,会通过发布/订阅向客户端发送两条消息:

PUBLISH __keyspace@0__:foo del
PUBLISH __keyevent@0__:del foo

客户端可以在一组类中选择Redis的通知事件,每个类都需要由唯一字符进行标识。

### Redis 键空间通知的启用方式 Redis 提供了键空间通知(Keyspace Notifications)功能,允许客户端订阅并接收与 Redis 数据库中键相关事件的通知。要监听 key过期事件,需要在 Redis 配置中启用 `notify-keyspace-events` 选项,并设置为包含 `Ex` 标志,表示仅监听键的过期事件。 --- ### 不使用 CONFIG 命令时的替代方案 如果由于安全策略或部署环境限制(如云服务)导致无法使用 `CONFIG` 命令来动态修改或查询配置,可以通过以下方式进行操作: 1. **通过静态配置文件启用键空间通知** 在 Redis 的配置文件 `redis.conf` 中直接设置: ```conf notify-keyspace-events Ex ``` 此设置确保 Redis 在启动时即启用了 key 过期事件的通知功能,无需运行时调用 `CONFIG SET` 或 `CONFIG GET` 命令 [^3]。 2. **在容器化部署中预设配置** 如果使用 Docker 等容器技术部署 Redis,可以在构建镜像时将配置文件挂载进容器,确保 Redis 实例启动时已启用键空间通知。例如,在运行容器时指定配置文件: ```bash docker run --name redis-container -v /path/to/redis.conf:/usr/local/etc/redis/redis.conf -d redis redis-server /usr/local/etc/redis/redis.conf ``` 3. **直接订阅 Redis 内部事件频道** Rediskey 过期事件会发布到名为 `__keyevent@<db>__:expired` 的频道中,其中 `<db>` 表示数据库编号(默认为 0)。应用可以直接订阅该频道,而无需依赖 `CONFIG` 命令进行配置检查。例如,使用 Spring Boot 可以自定义监听器如下: ```java @Component public class CustomKeyExpirationListener { @Autowired public CustomKeyExpirationListener(RedisConnectionFactory connectionFactory) { RedisConnection conn = connectionFactory.getConnection(); conn.pSubscribe((message, pattern) -> { String expiredKey = new String(message.getBody()); System.out.println("Key expired: " + expiredKey); }, "__keyevent@0__:expired".getBytes()); } } ``` --- ### 注意事项 - 在 Redis 集群模式下,需确保监听器连接到正确的主节点,因为集群环境下 key过期事件不会广播到所有节点 [^3]。 - 若使用 Redisson 客户端,可避免其自动检测机制,直接通过构造 `RedissonClient` 并指定服务器地址和配置,跳过对 `CONFIG` 命令的依赖。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值