如何在(io)Redis中为Key过期事件执行回调函数?
在Node.js的ioRedis中处理Redis键过期事件的正确方案
前提:开启Redis键空间通知
Redis默认关闭键空间通知,必须先开启才能接收过期事件,有两种配置方式:
- 临时生效(重启Redis后失效):执行Redis命令
config set notify-keyspace-events Ex - 永久生效:修改Redis配置文件
redis.conf,将notify-keyspace-events项设置为Ex(E代表键事件,x代表过期事件)
核心注意:使用独立的订阅客户端
不能用同一个ioRedis客户端同时处理读写操作和订阅事件——订阅模式下客户端会进入阻塞状态,只能处理订阅消息,无法执行其他命令,这也是你之前用同一客户端报错的原因。必须创建两个独立的客户端实例:
代码示例(ioRedis v4+)
import { Redis } from 'ioredis'; // 1. 用于常规读写操作的客户端 const redisClient = new Redis({ host: 'localhost', port: 6379, // 按需添加密码、数据库编号等配置 }); // 2. 专门用于订阅过期事件的客户端 const subscriber = new Redis({ host: 'localhost', port: 6379, // 注意:需与读写客户端使用相同的数据库编号 }); // 订阅指定数据库的过期事件(@0 对应数据库0,根据实际情况修改) subscriber.subscribe('__keyevent@0__:expired', (err) => { if (err) { console.error('订阅过期事件失败:', err); } else { console.log('已成功订阅过期事件'); } }); // 监听并处理过期事件 subscriber.on('message', (channel, expiredKey) => { if (channel === '__keyevent@0__:expired') { console.log(`键 ${expiredKey} 已过期,开始同步到数据库`); // 业务逻辑示例:从备份key中读取数据(因为原key已被Redis删除) redisClient.get(`backup:${expiredKey}`).then(data => { if (data) { // 将数据写入数据库 // db.save(expiredKey, JSON.parse(data)); console.log(`已将 ${expiredKey} 的数据同步到数据库`); // 同步完成后清理备份key return redisClient.del(`backup:${expiredKey}`); } }).catch(err => { console.error('同步数据到数据库失败:', err); }); } });
关键说明
- 订阅频道格式为
__keyevent@{db}__:expired,其中{db}是Redis数据库编号(默认是0),必须与读写操作的数据库一致。 - 过期事件并非精确触发:Redis通过定期扫描+惰性删除处理过期键,事件触发可能存在延迟。
- 提前备份数据:键过期后会被Redis删除,因此写入缓存时建议同时保存一份到不会过期的备份key(如
backup:${key}),确保触发事件时能拿到数据同步到数据库。 - 严格区分客户端:读写客户端与订阅客户端必须完全独立,避免状态冲突导致报错。
内容的提问来源于stack exchange,提问作者April Summers
相关产品推荐
相关产品推荐

