如何保证数据库的数据和Redis的数据一致性

实际项目中有可能会使用Redis缓存数据,那么在更新数据的时候如何保证数据库中的数据和Redis缓存的数据一致,缓存同步策略的选择是一个很重要的问题。网上有各种说法,大概总结有以下几种,看看每种方案是否可行以及存在的问题和适用场景。

1、先更新Redis,再更新数据库 (不可行 )

数据库是比较复杂的,而且还会涉及事务,因为超时等原因更新操作失败的可能性较大,这种方案很可能因为数据库更新失败,导致缓存和数据库的数据不一致。
在这里插入图片描述
如上图所示,如果第2步更新数据库失败了,那么缓存的数据被更新为20,和数据库值10不一致了。

这种情况可能会想到补救措施:数据库更新失败了再将Redis数据做逆向操作进行回退,但是如果Redis数据回退操作也失败了呢?甚至还要继续针对这种失败做重试?显然事情越做越复杂了,这种方式不可行。

2、先更新数据库,再更新Redis (部分场景可用,不推荐 )

上面的方案不可取,这种先更新数据库的是否就可行呢?假设有两个请求更新数据,时序图如下:
在这里插入图片描述

如果是并发量不高,对一致性要求没有特别高时,如上图更新完数据库再更新Redis没有问题。

在这里插入图片描述

如果是并发量较高,如图所示这种场景下虽然请求1和请求2先后完成数据库更新,但更新缓存时却是请求2和请求1的顺序,那就很可能会把旧数据更新到缓存中导致数据不一致。

3、先删除Redis,再更新数据库,访问的时候再加载数据到缓存 (不可行 )

这里同样以两个请求的场景为例,时序图如下:
在这里插入图片描述
从图上可以看到,当并发场景下如果请求1更新耗时较长,还未来得及更新数据库中的值,请求2已经先读取了旧值并加载到缓存中了。这种也会导致两边数据不一致,而且并发量很高的时候这种概率也会更大。

针对这个方案存在的问题可以在请求1更新完数据库后再对Redis做一次删除操作。也就是缓存双删

4、先删除Redis,再更新数据库,再删除Redis,访问的时候再加载数据到缓存(缓存双删)

在这里插入图片描述
这种方案一定程度上解决了方案3数据不一致的问题,但是也有一个关键点,如上图所示必须保证第6步删除缓存操作在第5步回写入缓存操作之后执行,否则还是会有问题。那么这又引出了另外两个问题:

  • 问题一:如何保证第二次删除缓存一定在回写后面执行呢?

关于双删的这个问题网上有方案是让请求1删除缓存时等待xxx毫秒,这个方案似乎可行,但是这个时间不好控制还是会存在一定风险。
另外也有博主给出的建议方案是将删除请求加入消息队列,异步串行化处理删除

  • 问题二:如果双删失败了怎么办?

同样的网上也有方案:给redis加一个缓存过期时间、删除加入消息队列利用消息队列的重试机制、自己记录删除失败进行重试等

5、先更新数据库,再删除Redis,访问的时候再加载数据到缓存

在这里插入图片描述
这种方案除了请求2第一次查询这一次不一致,还有另一个极端场景会存在数据不一致。请求1更新数据节点缓存刚好失效了,另一个请求2刚好这时读取缓存没有进而读了数据库旧值,如下图所示:
在这里插入图片描述
这个极端场景需要满足缓存刚好失效,而且请求2读取数据库及回写缓存耗时较请求1更新数据库更长,发生的概率非常小,可以忽略,所以相比较而言,方案5是最推荐的处理策略。

通过以上几种处理方案的分析,可以看到不管哪种方案都存在一定的问题,在满足实时性的条件下,尽量保证不一致出现的概率更低,或者不一致持续的时间非常短暂,避免长期不一致。非要满足强一致性可能就需要考虑使用锁的方案了。

总的来说,针对缓存同步更推荐的方式是,缓存中的数据不由数据更新操作主动触发,统一在需要使用的时候按需加载,数据更新后及时删除缓存中的数据。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值