您现在的位置是:首页 >技术教程 >缓存和数据库一致性问题网站首页技术教程
缓存和数据库一致性问题
情况一 先更新缓存再更新数据库
先更新缓存 再更新数据库 如果数据库更新失败 那我们缓存也没有意义 而且这个缓存也是需要计算的消耗资源的 所以不可取到
情况二 先更新数据库 后更新缓存
两个线程 线程A更新数据库 但是由于某些原因被阻塞了 也就是A更新后的数值没有被更新到缓存里面 这时候线程 B来了 将数值A由1改为了2 并成功写入缓存 此时缓存中A 的数值为2 但这时候线程A可以更新缓存了 又将缓存的数值改为了旧的数值1 此时就造成缓存中的数值并不是最新的数值
**情况三: 先删除缓存再更新数据库 **
此时也是有AB两个线程 请求A来更新数值A 先将缓存中删除了 此时线程A并未修改数据库中的数值A却被阻塞 这时候线程B来读取数据发现缓存中没有数值A 这时候去去读取数据库中A的数值读取到了A的旧数值 这时候线程A被调度 将A数值进行修改 但是线程B并没有读取到
依旧是 2 个线程并发「读写」数据:
缓存中 X 不存在(数据库 X = 1) 线程 A 读取数据库,得到旧值(X = 1) 线程 B 更新数据库(X = 2) 线程 B
删除缓存 线程 A 将旧值写入缓存(X = 1) 最终 X 的值在缓存中是 1(旧值),在数据库中是 2(新值),也发生不一致。这种情况「理论」来说是可能发生的,但实际真的有可能发生吗?
其实概率「很低」,这是因为它必须满足 3 个条件:
缓存刚好已失效 读请求 + 写请求并发 更新数据库 + 删除缓存的时间(步骤 3-4),要比读数据库 + 写缓存时间短(步骤 2 和 5)
仔细想一下,条件 3 发生的概率其实是非常低的。因为写数据库一般会先「加锁」,所以写数据库,通常是要比读数据库的时间更长的。
这么来看,「先更新数据库 + 再删除缓存」的方案,是可以保证数据一致性的。
所以,我们应该采用这种方案,来操作数据库和缓存。
情况四:先更新数据库再删除缓存
基本上都选择这一种方案来解决 但是也存在问题 :
解决上面问题的策略:
延迟删除: 请求B去睡觉 等A将旧数值写入到缓存中的时候B才去删除之前的旧的缓存设置新数值
上面都是单点的情况
下面主从分离架构下的缓存和数据库不一致的情况
问题:在binglog日志在向从库同步的时候 遇到网络故障 使从库的数据并没有与主库保持一致 导致线程B在查询从库的时候 读取到的仍为数据的旧值 并将旧值写入到了缓存中
对上面的架构进行改进: 在上面的架构上面添加了一个订阅binglog服务系统 当我的主库中数据进行更新的时候直接将数据更新到缓存中 这样可以保证我的缓存中一直都是最新的数据
但是当上面的binlog同步到redis后失败的情况怎么处理呢?
下面的情况:
为架构添加上了一个消息队列
参考文章
参考文章