web学习笔记编程技术学习与分享

Redis 缓存的三种更新策略与一致性

2026 年 08 月 10 日约 3 分钟阅读 后端与数据库

缓存与数据库的双写一致,没有完美方案,只有适合业务容忍度的方案。先把三种基本策略摆出来。

Cache Aside(旁路缓存,最常用)

读:先查缓存,命中返回;未命中查库、写缓存、返回。 写:先更新数据库,再删除缓存。

为什么是删除而不是更新缓存?两个原因:一是并发更新时,两个线程的写缓存顺序可能与写库顺序相反,缓存留下旧值;二是缓存的值往往是多表聚合的结果,写时计算容易和读取逻辑不一致。

为什么先库后删?反过来(先删缓存再更新库)时,删除到更新完成之间的读请求会把旧值重新填进缓存,且旧值存活到过期。先更库后删缓存的窗口小得多,只在「删除失败」时有问题——用延迟双删或订阅 binlog 补偿。

// 读
$v = $redis->get($k);
if ($v === false) {
    $v = $db->query(...);
    $redis->setex($k, 3600, $v);
}
// 写
$db->update(...);
$redis->del($k);

Read/Write Through

应用只和缓存交互,缓存层负责同步读写数据库。逻辑集中在中间件(如 Twemproxy 时代的一些方案),应用代码干净,但实现复杂,自研成本高。

Write Behind(异步写回)

写只落缓存,定期批量刷回数据库。性能最高,但宕机会丢数据,适合点赞数、浏览量这类可容忍丢失的计数场景,不适合订单。

一致性到底要多强

绝大多数业务不需要强一致,需要的是「最终一致 + 窗口可控」。落地时问两个问题:

  1. 脏读窗口多大能接受?秒级可接受就用删除 + 过期时间兜底;
  2. 删除失败怎么办?重试队列、订阅 binlog(Canal 类)都是成熟方案。

两条纪律

  • 缓存必须有 TTL。任何依赖「永远不失效」的缓存设计,出事时都没有退路;
  • 缓存 value 尽量自包含。读取时不做二次拼装,删除时不猜依赖了哪些 key。缓存一旦变成关系网络,失效顺序就会变成噩梦。
Redis缓存一致性