Redis缓存读写策略

Redis 缓存读写策略本质是在回答:

缓存(Redis)和数据库(DB)之间,数据如何读?如何写?如何保证一致性?

一、一致性问题

在使用 Redis 作为缓存时,数据一致性是一个核心问题。因为需要确定:

先更新数据库,还是先更新缓存?

先更新数据库,再更新缓存

先更新缓存,再更新数据库

所以:不管是先更新数据库还是先更新缓存,都会出现数据不一致问题


二、Cache Aside(旁路缓存 / 最常用)

读写流程

读流程

1
2
3
1. 先查 Redis
2. 命中 → 直接返回
3. 未命中 → 查 DB → 写入 Redis → 返回

写流程

1
2
1. 先更新 DB
2. 再删除缓存(不是更新缓存!)


为什么是“删除缓存”而不是“更新缓存”?

因为:

  • 更新缓存可能失败 → 数据不一致
  • 删除缓存更简单、安全(懒加载)

典型问题:缓存不一致

场景:

1
2
线程A:更新DB → 删除缓存
线程B:读缓存未命中 → 查旧DB → 写入缓存(旧数据)

出现:缓存脏数据


解决方案(重点)

  • 延迟双删
  • 加锁(分布式锁)
  • 使用消息队列异步删除
    • 使用消息队列来重试缓存的删除,优点是保证缓存一致性,缺点是对业务代码入侵
    • 订阅MySQL binlog+消息队列+重试缓存删除,优点是对业务代码无侵入,缺点是实现复杂

优缺点

优点

  • 实现简单
  • 使用最广(互联网大厂默认方案)

缺点

  • 存在短暂不一致问题

适用场景

  • 读多写少(电商、用户信息)

三、Read/Write Through(读写穿透)

由缓存系统(中间层)负责和 DB 交互


读写流程

读流程

1
2
3
1. 应用只访问缓存
2. 缓存命中 → 返回
3. 缓存未命中 → 缓存系统查DB → 写缓存 → 返回

写流程

1
2
3
1. 先查缓存
2. 缓存中不存在 → 直接更新DB
3. 缓存中存在 → 更新缓存 → 同步更新DB

优缺点

优点

  • 对应用透明
  • 一致性较好

缺点

  • 强依赖缓存系统
  • Redis 原生不支持(需要自己封装)

适用场景

  • 强一致性要求较高的系统

四、Write Back(异步缓存写入)

又叫:Write Behind


读写流程

写流程

1
2
1. 先写缓存
2. 异步批量写入 DB

读流程

1
只读缓存

优缺点

优点

  • 写性能极高(批量写 DB)
  • 减少 DB 压力

缺点(致命)

  • 数据可能丢失(缓存挂了)
  • 一致性弱

适用场景

  • 对一致性要求不高
  • 日志、统计、计数器

五、三种策略对比总结

策略 一致性 性能 复杂度 使用场景
Cache Aside ⭐⭐ ⭐⭐⭐⭐ ⭐⭐ 最常用
Read/Write Through ⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐ 中间件强依赖
Write Back ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ 高性能写

六、面试标准回答模板

可以直接这样说:

Redis 常用的缓存读写策略主要有三种:

第一是 Cache Aside(旁路缓存),也是最常用的。读的时候先查缓存,未命中再查数据库并回写缓存;写的时候先更新数据库,再删除缓存。这种方式简单高效,但会存在短暂的数据不一致问题。

第二是 Read/Write Through,由缓存系统负责读写数据库,应用只和缓存交互,一致性较好,但实现复杂,Redis 本身不直接支持。

第三是 Write Back(写回),写操作先写缓存,再异步写数据库,性能最高,但可能导致数据丢失,一般用于对一致性要求不高的场景,比如日志或统计数据。


七、进阶面试延伸

如何保证缓存一致性?

回答:

  • 延迟双删
  • 分布式锁
  • binlog + MQ
  • Canal 同步

为什么是“先更新DB再删缓存”?

因为:

  • 防止脏数据写回缓存
  • 保证 DB 是最终一致来源

为什么不用“先删缓存再更新DB”?

会导致:

  • 并发下缓存被写入旧数据