0
0
0

Redis 缓存更新策略与数据一致性

2023-02-24
2026-10-24
文章摘要
|

一、缓存维护的三种策略

策略

实现方式

数据一致性

内存淘汰

内存达到限制时,根据淘汰策略清理数据

较差

超时剔除

设置 TTL,过期后缓存失效

一般

主动更新

数据库变化时,主动删除或更新缓存

较好

注意:

  • Redis 默认内存淘汰策略是 noeviction,达到内存限制后不会主动淘汰旧数据,而是可能拒绝写入。

  • TTL 到期后数据逻辑上失效,Redis 通过惰性删除和定期删除等机制回收内存。

  • 实际开发中通常采用 主动删除缓存 + TTL 兜底。

  • 上表只表示一般情况下的数据新鲜度,不能认为主动更新就能保证强一致性。

二、Cache Aside(旁路缓存)

这是 Java 后端开发中常用的缓存读写模式。

1. 查询数据

查询 Redis
    ↓
是否命中缓存?
    ├── 是 → 直接返回
    └── 否 → 查询数据库
                 ↓
             写入 Redis(设置 TTL)
                 ↓
               返回数据

2. 修改数据

推荐顺序:

更新数据库
    ↓
数据库事务提交成功
    ↓
删除 Redis 缓存

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

因为并发更新时,多个线程写入缓存的顺序可能与数据库最终更新顺序不一致,导致旧数据覆盖新数据。

删除缓存更简单,下一次查询时会从数据库加载最新数据。

三、为什么不能先删除缓存,再更新数据库?

假设数据库中的商品价格为 100 元,准备修改为 200 元。

线程 A                   线程 B
   |                        |
删除 Redis 缓存              |
   |                        |
   |                    查询 Redis(未命中)
   |                        |
   |                    查询数据库(100元)
   |                        |
   |                    写入 Redis(100元)
   |                        |
更新数据库(200元)            |
   |                        |
   ↓                        ↓
数据库:200元          Redis:100元

结果:数据库和缓存出现不一致。

因此,推荐先更新数据库,事务提交后再删除缓存。

不过,即使这样操作,也不能完全避免极端并发情况下的数据不一致。

四、常见的三种缓存读写模式

模式

实现原理

特点

Cache Aside(旁路缓存)

应用负责数据库读写和缓存维护

最常用,灵活

Read/Write Through(读写穿透)

通过缓存层读写,由缓存层操作数据库

业务代码简单

Write Behind(异步写回)

先更新缓存,异步写入数据库

写入快,但存在数据丢失风险

Spring Boot 项目通常优先考虑 Cache Aside 模式。

五、实际开发注意事项

  1. 缓存设置 TTL:避免缓存数据长期不更新,也能在缓存删除失败时提供最终过期的兜底机制。

  2. 数据库事务提交后再删缓存:防止事务尚未提交,其他线程就读取旧数据并回填缓存。

  3. 处理缓存删除失败:可以使用重试、消息队列等机制保障删除最终完成。

  4. 注意并发回填问题:即使先更新数据库再删缓存,也可能出现旧查询结果延迟写回的情况;一致性要求高时,需要进一步设计版本校验等机制。

六、总结

Redis 缓存常用 Cache Aside + TTL。

  • 读操作:先查 Redis,未命中查数据库,再回填缓存。

  • 写操作:先更新数据库,事务提交后删除缓存。

  • 一致性保障:TTL 兜底、删除失败重试,必要时增加并发控制。

核心原则:数据库作为主要数据源,缓存用于提高读取性能。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论