内存淘汰 | 超时剔除 | 主动更新 | |
---|---|---|---|
说明 | 不用自己维护,利用Redis内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存。 | 给缓存添加TTL时间,到期后自动删除缓存。下次查询时更新。 | 编写业务逻辑,在修改数据库的同时更新缓存。 |
一致性 | 差 | 一般 | 好 |
维护成本 | 无 | 低 | 高 |
三种主动更新策略
- Cache Aside Pattern
企业常用此方法
由缓存的调用者,在更新数据库的同时更新缓存。
- Read/Write Through Pattern
缓存与数据库合为一个服务,调用者直接调用该服务,无需关心缓存一致性。
缺点是该服务开发成本高且成熟方案不多。
- Write Behind Caching Pattern
调用者只操作缓存,由其他线程异步的将缓存数据持久化到数据库,保证最终的一致性。
但是改方案存在一定的安全风险,因为持久化并不是实时进行的,如果Redis崩溃或断电会导致一一部分时间的数据丢失。
主动更新策略具体实现
采用Cache Aside Pattern
- 数据库更新时应删除旧缓存还是更新旧缓存?
- 更新缓存:每次修改数据库都更新缓存,会产生大量的无效写操作
- 删除缓存:更新数据库后删除旧缓存,有查询操作时再将数据更新到缓存中
- 如何保证缓存与数据库的操作同时成功或失败?
- 单体系统:将缓存与数据库操作放在同一个事务中
- 分布式系统:使用TCC等分布式事务方案
- 先操作缓存还是先操作数据库?
- 先删除缓存,再操作数据库
- 先操作数据库,再删除缓存
操作缓存的时间花费远远小于查询数据库的时间花费
应该先更新数据库,虽然两个方案都可能会发生不一致问题。但是方案二需要同时满足以下几点才回发生数据不一致问题:
- 正常线程查询数据时恰好缓存失效
而方案一仅需满足删除缓存后查询数据库前有线程切入即会发生数据不一致问题- 正常线程向缓存中写入数据时恰后修改缓存切入并在微秒时间内完成查询从查询数据库到写入缓存的操作。
方案二相对更加安全
总结
- 低一致性需求:使用Redis自带的内存淘汰机制
- 高一致性需求:主动更新并以超时剔除作为保底方案
- 读:
- 缓存命中直接返回数据
- 缓存未命中则先查询数据库,写入缓存,设定超时时间后再返回数据
- 写:
- 先写数据库,然后再删除缓存
- 确保数据库与缓存操作的原子性
- 读: