0
0
0
Redis 缓存更新策略与数据一致性
文章摘要
|
一、缓存维护的三种策略
注意:
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元结果:数据库和缓存出现不一致。
因此,推荐先更新数据库,事务提交后再删除缓存。
不过,即使这样操作,也不能完全避免极端并发情况下的数据不一致。
四、常见的三种缓存读写模式
Spring Boot 项目通常优先考虑 Cache Aside 模式。
五、实际开发注意事项
缓存设置 TTL:避免缓存数据长期不更新,也能在缓存删除失败时提供最终过期的兜底机制。
数据库事务提交后再删缓存:防止事务尚未提交,其他线程就读取旧数据并回填缓存。
处理缓存删除失败:可以使用重试、消息队列等机制保障删除最终完成。
注意并发回填问题:即使先更新数据库再删缓存,也可能出现旧查询结果延迟写回的情况;一致性要求高时,需要进一步设计版本校验等机制。
六、总结
Redis 缓存常用 Cache Aside + TTL。
读操作:先查 Redis,未命中查数据库,再回填缓存。
写操作:先更新数据库,事务提交后删除缓存。
一致性保障:TTL 兜底、删除失败重试,必要时增加并发控制。
核心原则:数据库作为主要数据源,缓存用于提高读取性能。
