Redis 过期提醒功能详解:基于键空间事件的实现
Redis 的 notify-keyspace-events
配置提供了键空间事件通知功能,可实时监听键的过期、删除、修改等事件,其中过期提醒是最常用的场景(如订单超时取消、会话过期清理等)。本文基于 Redis 6.0.10 版本,详解过期提醒的配置、订阅方式及实践注意事项。
核心原理:键空间事件(Keyspace Events)
Redis 的事件通知基于发布 - 订阅(Pub/Sub) 机制:当键发生特定操作(如过期、删除)时,Redis 会自动向指定频道发布事件消息,客户端通过订阅这些频道即可实时获取通知。
- 事件分类:
keyspace
事件:以__keyspace@<db>__:<key>
为频道,消息为事件类型(如expired
)。keyevent
事件:以__keyevent@<db>__:<event>
为频道,消息为键名(如order:1001
)。
(过期提醒通常关注keyevent
事件,直接获取过期的键名。)
配置开启过期提醒
配置 notify-keyspace-events
在 redis.conf
中设置事件通知类型,开启过期事件(x
)和键事件(E
):
1 | notify-keyspace-events Ex |
E
:启用keyevent
事件(按事件类型订阅)。x
:启用过期事件(键过期时触发)。
动态修改配置(无需重启)
通过 config set
命令临时开启(重启后失效,需同步到 redis.conf
):
1 | 127.0.0.1:6379> config set notify-keyspace-events Ex |
订阅过期事件
订阅指定数据库的过期事件
通过 PSUBSCRIBE
订阅带通配符的频道(支持所有数据库或指定数据库):
示例 1:订阅所有数据库的过期事件
1 | 客户端 1:订阅频道 __keyevent@*__:expired(* 匹配所有数据库) |
示例 2:订阅数据库 0 的过期事件
1 | 127.0.0.1:6379> SUBSCRIBE __keyevent@0__:expired |
触发过期事件
在另一个客户端设置过期键,验证通知是否生效:
1 | 客户端 2:设置键 order:1001 10秒后过期 |
10 秒后,客户端 1 会收到过期通知:
1 | 客户端 1 收到的消息 |
实践注意事项
1. 事件触发的延迟性
- 过期事件并非 “键过期瞬间” 立即触发,而是在键被实际删除时触发。
- Redis 对过期键的删除采用 “惰性删除 + 定期删除” 策略,因此事件可能延迟(最长不超过hz配置的扫描周期,默认 10 次 / 秒)。
- 若需严格时效性,建议结合业务逻辑主动检查(如定时任务)。
2. 订阅客户端的可靠性
- 发布 - 订阅机制是无状态的:若订阅客户端断线,重连后会丢失断线期间的事件。
- 解决方案:
- 使用 Redis Stream 或消息队列(如 Kafka)存储事件,客户端从队列消费(需手动实现)。
- 对关键业务,采用 “事件通知 + 定时补偿” 双重保障。
3. 性能影响
- 开启事件通知会消耗额外 CPU 和内存(尤其是高频过期场景)。
- 建议:
- 仅开启必要的事件类型(如只开启
Ex
而非A
所有事件)。 - 避免对大量短期过期键(如 1 秒内)启用通知,减少事件风暴。
- 仅开启必要的事件类型(如只开启
4. 键名解析
- 事件消息仅包含键名,需在键名中嵌入业务标识(如
order:1001
中的订单 ID 1001),便于后续处理。
应用场景
- 订单超时取消:
- 订单创建时设置
order:<id>
键,过期时间为订单超时时间(如 30 分钟)。 - 订阅过期事件,收到
order:<id>
时触发取消订单逻辑。
- 订单创建时设置
- 会话过期清理:
- 用户会话
session:<uid>
过期时,收到事件后清理关联资源(如临时文件)。
- 用户会话
- 缓存过期更新:
- 缓存键
cache:<key>
过期时,自动触发从数据库加载最新数据到缓存。
- 缓存键
v1.3.10