Post

缓存读写更新策略

缓存读写更新策略

缓存读写更新策略

  • 旁路缓存(Cache-Aside)
  • 读写穿透(Read/Write-Through)
  • 异步写回(Write-Back)

旁路缓存(Cache-Aside)

由缓存的调用者,在更新数据库的同时更新缓存。

读时:读缓存 –> miss后读DB –> 写缓存

写时:更新DB –> 删除缓存

旁路缓存又叫手动加载缓存,读取缓存、读取数据库和更新缓存的操作都在应用系统完成。

核心思想:应用程序代码直接与缓存和数据源进行交互。

优点:

  • 实现简单
  • 缓存中只包含实际请求数据

缺点:

  • 需要手动管理
  • 可能存在缓存不一致

场景:

  • 读多写少
  • 需要对缓存的加载和更新时间进行精细化控制

适合绝大多数场景,也是平时生产用的最多的。

我们再来分析一下 Cache Aside Pattern 的缺陷。

缺陷 1:首次请求数据一定不在 cache 的问题

解决办法:可以将热点数据可以提前放入 cache 中。

缺陷 2:写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率。

解决办法:

  • 数据库和缓存数据强一致场景:更新 DB 的时候同样更新 cache,不过我们需要加一个锁/分布式锁来保证更新 cache 的时候不存在线程安全问题。
  • 可以短暂地允许数据库和缓存数据不一致的场景:更新 DB 的时候同样更新 cache,但是给缓存加一个比较短的过期时间,这样的话就可以保证即使数据不一致的话影响也比较小。

读写穿透(Read/Write-Through)

缓存与数据库整合为一个服务,由服务来维护一致性。

调用者调用该服务,无需关心缓存一致性问题。

读时:从缓存系统读数据 –> 缓存系统:读缓存 ->miss则读DB –> 回写缓存

写时:将写入请求发给缓存系统 –> 缓存系统:miss则仅更新DB,hit则更新cache和DB

读写穿透一般是一起配合的。下面一起介绍:

读穿透

读穿透,是一种自动加载缓存的策略。

这种策略与旁路缓存的读取逻辑非常相似。只是旁路缓存是由应用程序从数据库获取数据并填充。而读穿透是由缓存系统从数据库获取数据并填充,就好像在Redis上面加了一层代理。在Redis和数据库之间插入了一个透明的加载过程,实现了关注点分离,应用程序只与缓存系统交互,由缓存系统管理 Redis 和数据库之间的数据同步。

优点:

  • 自动加载,数据库不在Redis的时候,自动触发从数据库加载数据操作,简化了应用程序的逻辑
  • 透明性,数据库不用关心数据是否在Redis中,读取数据的方式和直接从数据库读取数据一致

缺点:

  • 每次写入都需要等待缓存和数据库两步操作都完成,性能相较于其他模式较低
  • 并发加载,多个并发数据首次读取相同数据时,可能导致并发加载多次相同的数据(这点可以通过比如go的singlefilght避免惊群效应)

场景:

  • 读取频繁、不经常写入
  • 数据相对稳定,不经常变化。

写穿透

是一种同步直写策略。当应用程序写入数据的时候,数据会同步写入Redis和数据。

类似读穿透,写穿透把写入责任转移给缓存系统,由缓存抽象层来完成写Redis,更新数据库。

写穿透颠倒了旁路缓存填充缓存的顺序。

优点:

  • 数据一致性,缓存和数据库的数据总是最新的
  • 查询性能最优,应用程序写入完成后,缓存和数据库都是最新的

缺点:

  • 延迟:写入操作需要等待数据库确认,引入了一定的延迟
  • 高并发写入场景下,同步写入数据存储的过程可能成为瓶颈
  • 实现比较复杂,需要搭配特定模块或者组件

场景:

  • 强一致性要求
  • 读写比较平衡
  • 实时性要求比较高

典型的是金融场景,电商库存订单之类的

异步写回(Write-Back)

调用者只操作缓存,由其他线程异步的将缓存数据持久化到数据库,保证最终一致。

读时:miss后查DB并回写

写时:只更新cache,异步更新DB

当应用程序写入数据时,数据先写入缓存系统,由后台异步任务把这些变更批量写入数据库。

与写穿透类似,但是应用程序只与缓存系统交互,不必等待数据库更新完成。

写时:

  1. 应用程序写入:应用程序需要写入数据时,把写入请求发送给缓存系统,缓存系统把数据写入Redis,确保应用程序可以快速完成写入操作
  2. 消息队列:缓存系统维护一个消息队列,将写入Redis的数据添加到消息队列中
  3. 批量写入数据库: 异步任务将队列中累计的数据变更操作批量写入数据
  4. 确认写入完成:缓存系统更新相应的状态,标记已写入的数据变更操作,向应用程序返回写入操作已经写入完成的消息

实现了异步批量写入,避免每次写入都同步更新底层数据,提高写入性能。

通过异步队列和定期批量写入机制保证数据的最终一致性。

优点:

  • 提高写入性能
  • 降低写入延迟

缺点:

  • 数据一致性延迟(由于异步写入)
  • 系统故障或者异常情况下,尚未写入的数据可能丢失

场景:

  • 能容忍一定的数据一致性延迟,能容忍一定的数据丢失
  • 写入密集型场景或者需要批量处理数据

典型像是用户点赞,物联网数据上报

小结

这三种模式的核心区别在于:

谁来负责维护缓存和数据库之间的数据同步,以及写入操作是同步的还是异步的。

参考链接

  • http://elmer.icu/2024/11/20/%E7%BC%93%E5%AD%98%E8%AF%BB%E5%86%99%E7%AD%96%E7%95%A5/
  • 缓存更新策略和相应的数据一致性问题和方案.md
This post is licensed under CC BY 4.0 by the author.

Trending Tags