首页/数据/NoSQL 速查/旁路缓存模式与失效顺序
选型与架构50 条

旁路缓存模式与失效顺序

旁路缓存由应用负责读穿与写后失效:读 miss 回源并回填带 TTL 的值;写路径先落库再删除缓存键。反过来先删缓存再写库会留下旧值回填窗口,删除失败要重试补偿,TTL 作为最终兜底。

NoSQL 速查数据更新于 2026-10-13

旁路缓存怎么工作

旁路缓存由应用负责读穿与写后失效:读未命中就回源并回填带过期时间的值;写路径先落库再删除缓存键。缓存不参与数据库事务,一致性靠"删除加过期时间兜底"逐步收敛。

为什么是删除而不是更新

更新缓存要处理并发双写:两个写请求可能以相反顺序落到缓存与数据库,把旧值覆盖回去。删除是幂等操作,删错最多多一次回源,因此更安全。删除失败要进补偿队列重试,过期时间作为最终防线。

基本信息

读路径未命中回源并回填,过期时间加随机抖动防雪崩
写路径先写数据库,再删除缓存键
删除失败进补偿队列重试,过期时间兜底
替代策略write-through 同步写缓存与库,write-behind 异步刷库
适用范围缓存模式通用思路,Redis 等均适用

读写流程(伪代码)

读写流程(伪代码)
# 读:未命中回源并回填,过期时间带随机抖动避免同时失效
def get_user(uid):
    v = cache.get(key(uid))
    if v is not None:
        return v
    u = db.query(uid)
    cache.set(key(uid), u, ttl=300 + rand(60))
    return u

# 写:先落库,再删缓存;删除失败进入补偿队列
def update_user(u):
    db.update(u)
    if not cache.delete(key(u.id)):
        retry_queue.push(key(u.id))

典型使用场景

  • 热点读接口:用缓存挡住大部分读请求
  • 列表与详情:只缓存必要字段组合,控制缓存体积
  • 防雪崩:过期时间加随机抖动,避免大批键同时失效
  • 防击穿:热点键回源加互斥,避免并发同时打到数据库
  • 防穿透:对不存在的键做参数校验或布隆过滤

写入策略对比

策略行为风险
cache-aside写库后删缓存,读时回填删除失败出现旧值窗口
write-through写缓存同时写库(同步)写延迟变高
write-behind先写缓存,异步刷库进程崩溃可能丢写
只读缓存读回填,写只落库简单可靠,适合读多写少
优先用删除而不是更新缓存:并发双写下更新可能把旧值写回;删除天然幂等,配合过期时间最终收敛。
主从延迟期间从库读到的旧值可能被回填进缓存,读路径应固定读主库,或在延迟窗口内不复用从库结果,否则旧值会被长时间缓存。

易错点

  • 主从延迟期间从库读到的旧值可能被回填进缓存,读路径固定读主库或做延迟双删更稳
  • 缓存删除失败没有补偿时,旧值会一直保留到过期时间到点,需要监控删除失败率
  • 过期时间不设或设得过长,一旦写入路径出错就会长期读到旧值
  • 所有键用同一到期时间会导致缓存雪崩,回源压力瞬间打到数据库

数据来源与参考

  • Redis Docs: Client-side caching
  • AWS Architecture Blog: Caching challenges and strategies
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌