分布式系统中,缓存和数据库数据一致性问题总结

  分布式系统中,缓存和数据库数据一致性问题总结

            文章无格式见谅

  首先缓存的更新主要分两个机制(被动更新和主动更新缓存)

 日常使用中会存在三者:

         调用方(用户)  缓存  数据提供方(数据库)

被动更新

 客户端查询数据,会先去缓存看有没有数据,有直接返回,没有则去数据库查,然后放到缓存中,会设置一个过期时间t,当在t这个时间内都会去读取缓存的数据
      适合场景:对数据准确性和实时性要求不高的场景中,比如:商品的关注人数

主动更新:数据库更新完会直接更新缓存,来保证数据库和缓存都是最新的数据
       这样会出现几种情况,让我们一一解答
  先更新缓存,再更新数据库(数据不一致风险比较大,一般不使用)
  先更新数据库,再更新缓存(一般也不使用):如果缓存值是经过长时间计算去更新的话,这样会浪费系统的资源和性能,如果缓存值没人去查询的话,那么就更浪费资源了
  先删除缓存,再更新数据库(面试面的最多(双删),但不推荐使用):

1. 首先一个更新请求过来了,操作流程:先删除缓存-----更新数据库----再删除缓存
1.1 (会造成的问题)如果两个请求同时打过来(一个更新一个查询),先删除(这时缓存没数据),理想的情况下是先更新,然后再查询这样缓存就变成了新的数据
1.2 但是这个是理想的情况,因为大概率数据库的操作都是读比写快。这会导致还没更新完数据的时候缓存已经是旧的数据,这样就需要第二次删除缓存,也就是所谓的双删。
1.3 那么我们经常听到的延迟双删是什么呢,就是当更新完缓存的时候过一段时间再去删除缓存。那么这个时间我们怎么控制呢,没有一个准确的值,不同系统不同的时间。这样会造成系统的吞吐量下降。
1.4 补充一点
 之前有面试会问到,延迟双删有这几步,那么其中某一步失败了怎么办???
(1)删除缓存(刚开始就失败,就当请求没来过)
(2)更新数据库(更新失败那么事务就回滚)
(3)第二次删除缓存(主要问题点是在这个步骤):如果前面两步的操作没办法回滚的时候,那么这个时候最便宜的做法就是《硬着头皮往前走,重试重试再重试》。
(3.1)还可以借助消息队列,来重发处理失败的消息,如果继续失败,那么就把他丢到死信队列,通知人工介入等等。(但是这样会使我们的代码高度耦合),(可以借助canal或者类似于数据库binlog等机制来处理),重新写一个方法来一直读取我们失败的来不断的去删除,这样解耦会更好一点。

 先更新数据库,再删除缓存(最常用的)

 这也就是cache-aside模式:主要原理是系统大概率的操作都是读比写快

 说到这里就会有人不太理解:

有一种情况:两个请求,一个读A,一个更新B。前提:缓存没数据
1. A查缓存—缓存没数据—读数据库—(旧值)
2. B更新数据库—新值
3. B删除缓存
4. A将数据(旧值)写入缓存
上述这种情况是存在的,但是回到了最根本的一点—>没有绝对完美的解决方法
如果遇到了上述读比写还慢的情况,那么就再删除一次,(延迟双删)

 还有额外的两种方法(中小项目一般不用)
 1.Read/Write Through :直接操作缓存,不存在缓存是旧值的情况

  具体操作就是当程序启动的时候,将数据库的数据(字典表,订单信息等等)放到缓存中,不能等程序启动之后再去放(启动之后意味着可以接收请求)

 2.Write Behind :直接把缓存当作主数据库,一切都操作缓存,写完直接返回

  需要数据进行持久化的时候,需要介入异步或者队列来操作数据库             (缺点:缓存崩了,那么数据就丢了),                          (优点:减低了写操作的时间,增大了系统的吞吐量)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值