You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redis订阅键过期事件时如何获取过期键对应的存储值

问题根源

Redis原生键过期通知的机制决定了:过期事件推送时,对应的键已经被删除,通知消息体只会携带过期键的键名,不会附带键值。此时你在回调里直接对原键执行GET操作只会得到nil,这不是代码逻辑错误,是Redis本身的设计限制。

可落地的解决方案

方案1:影子键映射(生产环境首选)

实现成本最低,对现有业务侵入小,过期实时性和原生通知一致:

  • 写入业务键时,同步写入一个对应的影子键:键名加固定前缀做映射(比如原键是order:1001,影子键为shadow:order:1001),影子键的值存你需要在过期时获取的业务内容,TTL比原业务键长3~5秒(预留足够的回调处理延迟,避免网络波动导致读不到)
  • 监听到原键过期事件时,直接拼接影子键名读取对应值,处理完业务逻辑后主动删除影子键即可
    对应代码修改示例:
# 初始化配置逻辑不变
r.config_set('notify-keyspace-events', 'Ex')
pubsub.psubscribe(**{"__keyevent@0__:expired": event_handler})
pubsub.run_in_thread(sleep_time=0.01)

# 写入业务数据时同步写影子键
def set_biz_key(key, value, ttl):
    r.set(key, value, ex=ttl)
    # 影子键TTL比原键多预留3秒缓冲
    r.set(f"shadow:{key}", value, ex=ttl + 3)

def event_handler(msg):
    try:
        key = msg["data"].decode("utf-8")
        shadow_key = f"shadow:{key}"
        value = r.get(shadow_key)
        if value:
            # 这里就能拿到过期键关联的值,做后续业务处理
            real_value = value.decode("utf-8")
            print(f"过期键:{key},对应值:{real_value}")
            # 处理完主动删除影子键,避免冗余
            r.delete(shadow_key)
    except Exception as e:
        print(e)

注意TTL的缓冲时间要大于你服务订阅Redis通知的最大延迟,避免影子键提前过期。

方案2:逻辑过期替代Redis原生过期

不依赖Redis的自动过期能力,自行维护过期逻辑:

  • 写入键时不设置Redis层面的TTL,把业务值和过期时间戳打包存储,比如值结构为{"content":"业务数据","expire_ts":1723046400}
  • 启动后台定时任务,分批扫描所有业务键,判断到键的过期时间戳小于当前时间时,直接取出值完成业务处理,再删除对应键
    这个方案适合数据规模不大、对过期触发延迟容忍度高的场景,缺点是轮询存在秒级到分钟级的延迟,数据量大时要控制扫描批次和频率,避免阻塞Redis实例。

方案3:自定义Redis模块拦截删除事件

如果有Redis运维能力,可以开发自定义Redis模块,拦截键过期删除的流程,在键被实际删除前把键名和值一起推送到自定义频道,再由你的服务订阅这个频道拿值。这个方案灵活度最高,但运维和开发成本高,非特殊需求不推荐使用。

避坑提示:不要在回调里直接读取原键的值,过期事件触发时原键已经被Redis删除,所有读操作都会返回空。

内容的提问来源于stack exchange,提问作者Tlaloc-ES

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 15:54:22