保证数据库与缓存一致性的几种策略


分布式系统下,数据库和缓存本来就无法保证强一致性,因为数据库+缓存的操作并不是原子操作,所以在服务过程中,我们可以忍受一段时间内的数据不一致,但是一定要保证最终一致性。

而一般来说,有三种更新策略:

  • 先更新数据库,再更新缓存
  • 先更新缓存,再更新数据库
  • 先更新数据库,再淘汰缓存
  • 先淘汰缓存,再更新数据库

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

这绝对不是个好方法,考虑这么一种情况:

当更新缓存成功,而更新数据库失败时,就直接造成了数据不一致。所以说这种策略几乎没啥人会使用

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

这也不是个好办法,考虑这么一种情况:

1.线程1将数据库更新为A,线程2将数据库更新B

2.线程2将缓存更新为B,线程1将缓存更新为A

那么这会造成不一致:数据库中,B把A覆盖了(这是正确的逻辑),但是在缓存中,A把B覆盖了。就会造成数据不一致了。造成这个问题的罪魁祸首就是整个操作是非原子性的,有线程安全问题。

再考虑这么一种情况:如果在一个读多写少的场景,数据的更新非常频繁(包括数据库中和缓存中),有可能缓存中的数据被频繁更新,但是有一些数据压根就从来没有被访问过,然后又被新值覆盖了,这样就会造成浪费。

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

这是一种比较常用的方法。如果淘汰缓存成功,而更新数据库失败,这只会稍微降低缓存的缓存的命中率。相比于不一致性,这是可以接受了。

当然这个方法也无法完全保证一致性,考虑这样一种情况:当缓存淘汰之后,开始执行数据库更新工作,但是这个操作还没做完,就有另一个读请求落在了数据库上,读到了旧值,并把旧值放进了缓存中,那么就会出现缓存数据库不一致了。

上面的情况是在单机情况下,在读写分离,也就是拥有主从服务器的架构中,这种情况更明显:淘汰了缓存,主服务器完成更新,但是主从同步还未完成,在这期间,读请求落在了从服务器上,由于主从同步还未完成,就会读到旧值,并且放到了缓存中,也就造成了数据不一致

解决方法:

  • 简单暴力,使用分布式锁,将读写串行化,但是这样会大幅度地降低吞吐量
  • 采用延时双删策略:实现也很简单,就是淘汰完缓存,然后更新数据库之后,休眠一段时间,然后再去删除缓存中的值。这样就可以删除缓存中不一致的数据。当然直接休眠一段时间会降低吞吐量,可以启动一个线程,异步地完成这个操作

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

如果更新数据库失败,则直接返回,不会有任何影响;若更新数据库成功,淘汰缓存失败,此时会直接造成数据不一致。当然,及时全部操作成功,也会造成数据不一致,比如:

线程1查询一个旧值,然后线程2更新数据为新值,然后把缓存删除,线程1才姗姗来迟地把缓存更新为旧值。这样就造成数据不一致。

解决方法:同样使用延时双删策略

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值