多级缓存一致性方案

1. 背景

目前大部分的项目都是读多写少,在读取数据时经常会使用Redis缓存技术来加快读响应时间和减少服务数据库压力,在使用缓存时,会面临一个问题,如何保障缓存与数据库的数据一致。

2. 缓存更新策略

常见的缓存更新策略

  • Cache Aside 旁路策略
  • Read/Write Through 读写穿透策略
  • Write Behind 又叫Write Back 异步写入策略
  • Refresh Ahead 预加载策略
  • CDC 监听数据变更来更新缓存

2.1 Cache Aside 旁路策略

  • 最常见的缓存模型,在该策略中,缓存不是数据存储流程中的必需环节,而是位于数据库旁边作为性能优化手段
  • 读取数据,如果缓存中存在,直接返回缓存中的数据,如果不存在从数据库查询,并将数据放在缓存中
  • 更新数据,首先更新数据库,再删除缓存
  • 这种方案在并发场景下可能会出现数据不一致的情况,比如A线程查询缓存没数据,查数据库结果为1,但还没设置到缓存,B线程更新数据库结果为2,并删除缓存,这时候A线程再去设置了查询到的结果1,这样数据就不一致了,或者应用程序在删除缓存时没有成功,也会出现不一致的情况,这些概率都比较小
  • 延迟双删,为了解决上面的问题,可以通过延迟双删的方式来保障数据的最终一致性,更新数据库后,删除缓存,休眠一段时间后,再次删除缓存,休眠时间更新业务从数据库读取数据的耗时来评估
  • 如果有分布式事务,导致数据回滚,缓存无法回滚

2.2 Read/Write Through 读写穿透策略

  • 应用程序只操作缓存,再由缓存系统与数据库交互,一般会在同一个事务中进行,需要保障缓存与数据库的一致性
  • 适合一致性要求高的场景

2.3 Write Behind 异步写入策略

  • 应用程序只操作缓存,缓存层连接到数据库
  • 应用程序使用缓存进行读写操作
  • 缓存将任何更改的数据异步同步到数据库
  • 适合写多的场景

2.4 Refresh Ahead 预加载策略

  • 缓存会在数据过期之前主动刷新数据,而不是等到数据被请求时才进行刷新
  • 缓存在后台异步地执行数据刷新操作,以确保数据的最新版本被加载到缓存中。
  • 优点:提高了缓存的命中率和访问速度

2.5 CDC更新缓存

CDC (Change Data Capture) 是一种数据复制和同步策略,用于监听数据库中的数据变化,并传输到其他系统或数据存储中,从而保持不同系统间的数据一致性和同步,常见的工具如:Canal、Debezium、FlinkCDC,CDC具有以下优点

  • 实时性:CDC 可以捕获数据库中发生的变化,并将这些变化实时传送到其他系统或数据存储中。这意味着数据同步可以几乎实时地进行,从而确保不同系统之间的数据保持最新。
  • 精确性:CDC 可以捕获单个数据库操作的细粒度变化,例如插入、更新和删除操作,因此可以精确地了解数据的变化情况,而无需进行全表扫描或比较。
  • 性能良好:由于 CDC 只捕获发生变化的数据,而不是整个表或数据库,因此可以减少对系统资源的消耗,提高性能效率。这对于大型数据库和高频率变化的系统尤其重要。
  • 避免数据丢失:通过实时捕获和传送数据变化,CDC 可以避免数据丢失或遗漏,确保所有变化都得到同步和处理。
  • 多系统集成:CDC 可以用于将数据从一个系统同步到多个目标系统,支持多系统之间的数据集成和同步,从而实现系统之间的数据共享和协同工作。
  • 灵活性:CDC 可以根据需求配置和定制,支持不同的同步模式和数据传输方向,适用于各种复杂的数据集成和同步场景。
  • 监听数据库的日志,再更新缓存,与业务结构,达到近乎实时的同步

3. 多级缓存

将不同性能和不同特征的缓存技术结合在一起,最大程度的减少系统压力,提高更快的响应速度和更大的并发量

3.1 本地缓存+分布式缓存


优先读取本地缓存,本地缓存没有读取redis缓存,redis没有再读数据库。使用本地缓存可以有效减小由于热点Key导致流量集中在Redis的某一个节点导致的Redis崩溃

3.2 nginx+lua+分布式缓存


Tomcat默认最大的线程数为200,最大支持10000连接数,使用Nginx+OpenResty+Lua直接访问Redis读取数据,可以绕过应用程序,极大减少应用程序的访问压力

3.3 多级缓存数据一致性


结合上述内容,可以通过Nginx+Lua+CDC来实现多级缓存的数据一致性