Redis与MySQL缓存双写一致性问题
先来看一些常见的面试题

读写缓存

我们的读写缓存分为两种情况
- 同步直写缓存策略:完成第二部立即回写Redis
- 异步缓写缓存策略:不急立即写回Redis
- 正常业务运行中,MySQL数据变动了,但是可以在业务上容许出现一定时间后才作用于Redis,比如仓库、物流系统
- 异常情况出现了,不得不将失败的动作重新修补,有可能需要借助kafka或者RabbitMQ等消息中间件,实现重试重写
那么代码应该怎么写呢?下面是初级版本,业务逻辑并没有写错,对于小厂中厂(QPS<=1000)可以使用,但是大厂不行

但是以上代码有问题,如果大量请求进行第一个查询Redis为空,那么后续判断都会进行MySQL查询,打高MySQL的IO
双检加锁策略
那么如何解决上述问题呢?
多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个互斥锁来锁住它。其他线程走到这一步就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存


和双重检查锁思路一样,值得借鉴

数据库和缓存一致性的几种更新策略
给缓存设置过期时间,定期清理缓存并回写,是保证最终一致性的解决方案。
我们可以对存入缓存的数据设置过期时间,所有的写操作以MySQL数据库为准,对缓存操作只是尽最大努力,如果数据库写入成功,缓存更新失败,那么只要达到过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存,达到一致性,切记,要以MySQL的数据库写入为准
- 先更新数据库,再更新缓存
- 先更新缓存,再更新数据库
- 先删除缓存,再更新数据库
- 先更新数据库,再删除缓存
先更新数据库,再更新缓存
异常情况1:

异常情况2:

先更新缓存,再更新数据库
不推荐,业务上一般把MySQL作为底单数据库,保证最后解释

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


为了解决这个问题,所有有了延时双删
延时双删

优化版:

先更新数据库,再删除缓存(推荐)
异常情况:

虽然这个也有问题,但是是大厂比较推荐的方法
canal结合binlog


最终方案选择

总结

canal

Redis与MySQL缓存双写一致性问题
http://example.com/2023/12/26/Redis与MySQL缓存双写一致性问题/