缓存一致性问题续

在前面的博客中,我有介绍过缓存一致性问题。本篇我打算详细分析各种情况,给出最优的解决方案:

其中保证缓存一致性问题常有以下四种方式:

  1. 先更新缓存,再更新数据库
  2. 先更新数据库,再更新缓存
  3. 先删除缓存,再更新数据库
  4. 先更新数据库,再删除缓存

场景一和场景二很少使用,因为都存在脏数据的可能性。导致原因基本类似:先进行的操作成功,但后进行的操作失败。一般线上更多使用场景三或者场景四

对于场景三,单线程场景下可以保证缓存一致性,但多线程场景下仍有可能出现脏数据情况:

线程a 是写请求,线程 b 是读请求,两个线程并发执行:

  1. 线程 a 删除缓存,准备执行更新数据库操作
  2. 线程 b 判断缓存中没数据,去数据库读取到还未更新的数据
  3. 线程 b 刷新脏数据到缓存中
  4. 线程 a 接着执行,完成更新数据库操作

对于上述问题,最简单的解决方法就是延时双删除:先删除缓存,再更新数据库,延迟一会再删除缓存

这里延时一会的主要原因在于删的过快,读取的线程可能还没有将脏数据刷新到缓存中,具体延迟的时间可以根据业务自行估算

上面说的是线程交替执行的场景,实际即使线程没有交替执行仍有可能造成脏数据问题:线程 a 删除缓存,并更新数据库成功。线程 b 发现缓存没有数据,从数据库读取到脏数据。既然线程 a 已经更新成功,为什么线程 b 还能读取到脏数据呢,实际道理很简单:数据库主从机制:

一般公司数据库线上一定会做读写分离,涉及到读写分离一定涉及到数据库同步延时问题。数据库压力比较大时,可能得过几秒才能同步到最新的数据,此时从库读取到数据一般就是脏数据。对于该问题解决办法也很简答,对于刷新缓存的读请求,强制在主库执行

除了上面提到的双删法,还有一种比较麻烦的思路:通过内存队列记录任务,依次执行。比如当缓存中没有数据时,将读取缓存操作和更新缓存操作依次打入队列。此时更新数据库操作肯定排再前面,也可以保证读取的总是读取到最新数据。需要注意的一点是,不是每个请求都需要去执行读取和更新,如果队列中已经存在读取操作,直接等待队列执行完从缓存获取即可

对于场景四同样存在脏数据问题:更新数据库成功,删除缓存失败。此时缓存中的数据就和数据库中的数据不一致。解决办法有很多,try-catch 括起来删除缓存操作,如果执行失败打标记,新增其它删除逻辑,比如发 mq 异步再删除或者线程池异步再删除

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值