缓存和数据库的一致性问题

缓存的用法

在项目中我们经常这样用缓存来缓解数据库的压力:
在这里插入图片描述

但是对于写缓存,你知道怎么设计方案,保证缓存与数据库的数据一致性吗?

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

在这里插入图片描述

请求B是最后请求的,那么应该是他最后更新缓存为正确的数据,但是有可能请求A处理的更慢,所以请求A更新了最后的缓存。

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

先删除缓存,数据库还没有更新成功,此时如果读取缓存,缓存不存在,去数据库中读取到的是旧值,然后更新缓存,缓存不一致发生。如图:
在这里插入图片描述

延时双删

上面的问题可以用延时双删的方案来解决,思路是,更新完数据库之后,再sleep一段时间,然后再次删除缓存。

sleep的时间要对业务读写缓存的时间做出评估,sleep时间大于读写缓存的时间即可。

流程如下:
在这里插入图片描述

  1. 线程1删除缓存,然后去更新数据库

  2. 线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存

  3. 线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除

  4. 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值

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

当然,这样也会有并发问题。
比如:

在这里插入图片描述

但是数据库读操作速度远快于写操作,所以存在脏数据的可能性为0。
当然如果您问,如果真的存在怎么办?
简单,双删就行了,即第一次删除缓存之后,等待一段时间重新再删一次。
当然您如果还问,删除缓存失败了怎么办,解决方法如下:
在这里插入图片描述

即引入消息队列,删除缓存失败的记录下来重复删除,直到成功为止。如此一来,万无一失。

其他解决方案

设置缓存过期时间

每次放入缓存的时候,设置一个过期时间,比如5分钟,以后的操作只修改数据库,不操作缓存,等待缓存超时后从数据库重新读取。

如果对于一致性要求不是很高的情况,可以采用这种方案。

这个方案还会有另外一个问题,就是如果数据更新的特别频繁,不一致性的问题就很大了。

在实际生产中,我们有一些活动的缓存数据是使用这种方式处理的。

因为活动并不频繁发生改变,而且对于活动来说,短暂的不一致性并不会有什么大的问题。

总结

首先,我们要明确一点,缓存不是更新,而应该是删除。

为什么呢?
我们用先更新数据库,再删除缓存来举例。

如果是更新的话,那就是先更新数据库,再更新缓存。

举个例子:如果数据库1小时内更新了1000次,那么缓存也要更新1000次,但是这个缓存可能在1小时内只被读取了1次,那么这1000次的更新有必要吗?

反过来,如果是删除的话,就算数据库更新了1000次,那么也只是做了1次缓存删除,只有当缓存真正被读取的时候才去数据库读取。

删除缓存有以下两种方式:

1.先删除缓存,再更新数据库。解决方案是使用延迟双删。

2.先更新数据库,再删除缓存。解决方案是消息队列或者其他binlog同步,引入消息队列会带来更多的问题,并不推荐直接使用。
针对缓存一致性要求不是很高的场景,那么只通过设置超时时间就行了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的架狗师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值