缓存失效的常见触发场景包括:用户修改商品价格、管理员更新配置、订单状态变更等业务动作;需精准删除关联多个key的数据,并绑定失效逻辑到数据变更点。

缓存失效的常见触发场景有哪些
缓存失效不是“要不要删”,而是“什么时候删、删哪些、删完怎么补”。真实系统里,cache.delete() 或 cache.clear() 很少单独出现,它总和业务动作耦合:用户修改了商品价格、管理员更新了配置、订单状态从“待支付”变成“已支付”。
- 用户提交表单后,需立即让对应商品详情页的缓存(key 含
product:123)失效,否则前端看到旧价格 - 一个数据库行被更新,但缓存里可能有多个 key 关联它(如
user:456:profile、user:456:orders:recent),得批量清理 - 某些缓存是组合生成的(比如首页推荐列表依赖用户标签 + 商品库存 + 活动开关),任一上游数据变动,都应触发该缓存失效
不区分场景统一用 timeout 被动过期,会导致脏数据窗口不可控;全靠手动 delete 又容易漏——关键在把失效逻辑“绑定”到数据变更点。
Django Cache 中如何安全地批量删除带通配符的 key
Django 默认缓存后端(如 LocMemCache、RedisCache)都不支持原生通配符删除。直接写 cache.delete("user:") 是无效的,它只会尝试删一个叫 user: 的字面 key。
- Redis 后端可用
cache._cache.keys("user:*")(注意是私有属性,仅限redis-py后端),再循环cache.delete(key);但高并发下 keys 命令阻塞 Redis,生产禁用 - 更稳妥的做法是“主动记录 key 映射”:写缓存时,用一个集合 key(如
cache_keys:user:456)存下所有关联 key,失效时先取集合、再批量删、最后清空该集合 - 如果用
django-redis,可启用KEY_PREFIX配合cache.clear()清局部命名空间,但要注意它会清整个前缀下的所有 key,包括临时缓存
别依赖 cache.keys() 做线上清理逻辑,它不是原子操作,且部分缓存后端根本不实现该方法。
立即学习“Python免费学习笔记(深入)”;
使用 time-based 失效时,为什么有时缓存没按预期刷新
timeout 参数看似简单,但实际受三个因素干扰:
- 缓存后端时间不同步:Django 进程所在机器时间 vs Redis 服务器时间偏差 >1 秒,就可能导致 key “提前消失”或“滞留”
-
timeout=0在某些后端(如LocMemCache)表示“永不过期”,但在PyLibMC中可能被转成最大整数,行为不一致 - 并发读写时,多个请求同时发现缓存 miss,都去重建,结果写入多份相同值——这不是失效问题,但会让“刚刷新就又脏了”的错觉更明显
建议:对时效敏感的数据(如库存、秒杀开关),不用纯 timeout,改用“主动失效 + 短 timeout 保底”双机制。例如设 timeout=30,同时在库存变更时显式 cache.delete("stock:789")。
缓存穿透与失效雪崩的防御要点
缓存穿透(查不存在的 key,反复打穿缓存直击 DB)和失效雪崩(大量 key 同时过期,DB 瞬间被压垮)本质都是失效策略没兜住。
- 对穿透:写缓存时,对查无结果的 key 也存一个空值(如
cache.set("user:999999", None, timeout=60)),并加前缀区分(如empty:user:999999),避免和真实None混淆 - 对雪崩:不要让大批 key 共享同一
timeout。可用随机偏移,例如timeout=300 + random.randint(0, 60);或者按业务重要性分层设置过期时间(核心配置 5 分钟,用户偏好 30 分钟) - 更关键的是,失效后重建缓存的过程必须加锁。用
cache.add("lock:product:123", "1", timeout=5)判断是否获得重建权,没抢到的请求等待或回退默认值,而不是各自查 DB
空值缓存和分布式锁不是可选项,是失效策略上线前必须验证的环节。










