Redis双写一致性

348 阅读3分钟

读写缓存2种策略

同步直写策略

  1. 写数据后也同步写redis缓存,缓存和数据库中的数据一致
  2. 对读写缓存来说,要保证缓存和数据库中的数据一致,就要采用同步直写策略

异步缓写策略

  1. 正常业务运行中,MySQL数据变动了,但是可以在业务上容许出现一定时间后才作用于redis,比如仓库、物流系统
  2. 异常情况出现了,不得不将失败的动作重新修补,有可能需要借助Kafka或者RabbitMQ等消息中间件,实现重试重写

双检加锁校验

没加锁,高并发情况下会把Redis打爆

image.png

多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个互斥锁来锁住它。

其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。 后面的线程进来发现已经有缓存了,就直接走缓存。

image.png

数据库和缓存一致性的几种更新策略

*给缓存设置过期时间,定期清理缓存并回写,是保证最终一致性的解决方案

我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存,达到一致性,切记,要以mysgl的数据库写入库为准。

  1. 更新数据库,再更新缓存(×) image.png

image.png

  1. 先更新缓存,再更新数据库(×) 不推荐,因为我们最好把MySQL作为底单数据库,保证最后解释

image.png

  1. 先删除缓存,再更新数据库(×) image.png

image.png

image.png

image.png

image.png

解决方法

延迟双删

image.png 加上sleep的这段时间,就是为了让线程B能够先从数据库读取数据,再把缺失的数据写入缓存然后,线程A再进行删除。所以,线程A sleep的时间,就需要大于线程B读取数据再写入缓存的时间。这样一来,其它线程读取数据时,会发现缓存缺失,所以会从数据库中读取最新值。因为这个方案会在第一次删除缓存值后,延迟一段时间再次进行删除,所以我们也把它叫做“延迟双删”。

延时双删相关问题

线程A该休眠多久再执行第二次删除?
答:线程A sleep的时间,需要大于线程B读取数据再写入缓存的时间。
这个时间怎么确定呢?
第一种方法:
在业务程序运行的时候,统计下线程读数据和写缓存的操作时间,自行评估自己的项目的读数据业务逻辑的耗时,以此为基础来进行估算。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上加百毫秒即可。 这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

第二种方法:
新启动一个后台监控程序,比如后面要讲解的WatchDog监控程序,会加时

这种同步淘汰策略,吞吐量降低怎么办?

image.png

  1. 先更新数据库,再删除缓存

image.png

缓存更新失败

image.png

image.png