Redis Keyspace Notifications 是什么?适合做可靠事件吗?
简化版
Keyspace Notifications 是 Redis 的键空间事件通知能力,可以通过 Pub/Sub 订阅 key 过期、删除、修改等事件。但它不适合做可靠事件系统,因为 Pub/Sub 不持久化、客户端断开会丢消息,事件也不保证像消息队列那样可重放和确认。
详细版
开启相关配置后,Redis 可以在 key 发生变化时发布事件。例如订阅过期事件,可以收到某个 key 过期的通知。
它适合轻量监听、调试、非关键异步触发,例如缓存旁路提醒、临时状态观察。但如果业务要求“事件必须到达、不能丢、失败可重试”,应该使用消息队列、Stream 或数据库状态表,而不是依赖 Keyspace Notifications。
面试重点是讲清楚:它是通知,不是可靠消息。
完整版教学
一、Keyspace Notifications 做了什么
Redis 可以在 key 被修改、删除、过期、淘汰时,通过 Pub/Sub 发布事件。订阅者收到事件后可以执行后续逻辑。
例如你想观察 session key 过期,可以订阅过期事件,收到 session:1001 过期后清理一些旁路状态。
CONFIG SET notify-keyspace-events Ex
PSUBSCRIBE __keyevent@0__:expired
这里 E 表示 keyevent 事件,x 表示 expired 事件。不同字母组合控制不同事件类型。
二、为什么它不是可靠消息
Keyspace Notifications 基于 Pub/Sub,而 Redis Pub/Sub 的语义是在线推送。订阅者断开期间,消息不会保存;消费失败,也没有 ack、重试、死信队列。
这意味着它不能承担核心业务一致性。例如“订单超时未支付自动取消”不能只靠 Redis 过期通知,因为应用重启或网络抖动时可能漏掉取消事件。
可靠事件需要可持久化、可重放、可确认。Keyspace Notifications 更像“广播提醒”,不是“任务账本”。
三、过期事件的时间也不是精确定时器
Redis key 过期删除有惰性删除和定期删除机制。key 到达 TTL 后,不一定在那个毫秒立刻删除,也不一定立刻发出事件。
假设一个 key 设置 10 秒过期,你可能在 10.1 秒收到事件,也可能更晚,取决于访问、定期扫描和实例负载。
SETEX order:1 10 pending
第 10 秒:逻辑上已过期
第 10.3 秒:Redis 删除 key 并发布 expired 事件
因此它不适合作为严格定时调度器。
四、适合和不适合的场景
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 观察缓存删除 | 适合 | 可丢、辅助性质 |
| 本地进程刷新旁路状态 | 适合 | 失败影响小 |
| 订单超时取消 | 不适合 | 不能漏 |
| 延迟任务队列 | 不适合 | 无 ack 和重放 |
| 审计日志 | 不适合 | 需要持久化 |
如果只是“知道一下发生了什么”,它很好用;如果是“必须做成某件事”,就要换方案。
五、可靠替代方案怎么选
如果需要可靠消息,可以用消息队列或 Redis Stream。Stream 支持消息持久化、消费组、ack 和 pending 列表,比 Pub/Sub 更适合任务消费。
如果是订单超时,可以用数据库状态 + 定时扫描 + MQ 延迟消息 + 幂等取消组合。即便某条消息丢了,扫描任务也能兜底。
可靠系统通常不是靠一个过期通知完成,而是靠“状态可查、操作幂等、失败可重试、定期对账”。
六、常见误区与追问
- 误区:收到过期事件就等于定时任务可靠执行。 订阅断开会丢消息,过期触发也不保证精确时间。
- 误区:Keyspace Notifications 默认就开。 它需要配置事件类型,开启过多事件也会有额外开销。
- 误区:Redis 发了事件就能保证业务成功。 事件只是通知,业务处理失败没有自动重试语义。
- 追问:为什么订单超时不能只靠它? 订单取消不能漏,而 Pub/Sub 不持久化、不 ack、不可重放。
- 追问:Redis Stream 能替代它吗? Stream 更适合可靠消费,但仍要设计幂等、重试和消息保留策略。
七、加强记忆
记忆钩子:Keyspace Notifications 是门铃,不是快递单;门铃响了你可以知道有人来过,但不能拿它证明包裹一定送达、签收、可追踪。
回答这题时先介绍能力,再马上划清边界:通知可丢、时间不精确、无确认重试。最后给出 Stream、MQ、数据库扫描这些可靠替代方案,就能显得很稳。