探讨缓存一致性问题

探讨缓存一致性问题

本文只探讨只读缓存,即只对缓存进行读取、写入、删除,不进行更新操作

前言

数据库的读写性能上限是比较低的,工程中经常在数据库前面加一层缓存,可能是Redis或者本地缓存。既然有缓存,那么不可避免的会遇到缓存一致性问题。

缓存一致性的概念

缓存一致是指:缓存有值,且值等于数据库中的值,如果缓存中的值不等于数据库中的值,则认为是不一致。

缓存的操作场景

一般操作缓存有两种场景:新增和更新(修改、删除)。

新增

操作流程:

  1. 向数据库写入新的数据
  2. 读取时,缓存中不存在,则进行回源并更新缓存,这时数据库和缓存是一致的
    在这里插入图片描述

更新

更新缓存的场景内其实还有两个细分场景,主要差别是更新的顺序不同。如下:

  1. 先更新数据库,后删缓存
  2. 先删缓存,后更新数据库
    在这里插入图片描述

问题以及解决方案

新增场景下不会有不一致的问题,因为读取是从数据库读取并写入到缓存中的,所以始终是一致的。
更新场景下会遇到两个问题:

  1. 单线程下的操作失败问题
  2. 并发情况下的顺序问题

单线程情况

因为更新是有两个操作步骤,即更新数据库和删除缓存,如果后续步骤失败了,那就会才造成数据不一致,例如先更新数据库但是删除缓存失败了,那么后续的请求会直接读取到缓存中的旧值;反而如果是先删除缓存,但是后续更新数据库失败了,影响倒是不大,后续的请求发现缓存不存在,会回源正确的数据。
在这里插入图片描述

解决方案
消息队列+重试

将更新操作生成消息,暂存在消息队列中,当删除缓存成功后,将消息从消息队列中丢弃,当删除失败时,执行失败策略,从消息队列中取出消息进行重试,重试超过一定次数则上报。
在这里插入图片描述

订阅binlog变更日志

创建一个更新服务订阅数据的binlog变更日志,收到数据库变更后删除缓存

并发情况

并发情况下需要对两个更新顺序分别分析

先删除缓存 后更新数据库

线程A删除缓存后,线程B进行读取,发现数据不存在,则进行回源,此时缓存值是旧的,最后线程A才将更新的新值写入数据库。
在这里插入图片描述

解决方案
  1. 设置缓存过期时间+延时删除
    设置缓存过期时间,这样数据过期后还可以再次拉取数据库进行更新,达到最终一致性。即使数据不一致,但造成的影响时间范围比较小,。或者使用延时队列在更新完数据库后再次进行删除缓存,这样即使在延时期间有其他线程读取了旧数据并更新缓存,后续也一定会再次进行更新。
先更新数据库,后删除缓存

线程A更新数据库后,还没删除缓存,这时线程B进行读取,读取到了缓存中的旧值。
简单并发问题
或者如果数据库采用主从架构时,线程A更新完数据库并删除缓存后,线程B发现缓存无数据进而向从数据库拉取数据并写缓存,如果这时主数据库的数据还未同步到从数据库时,就会导致数据不一致。
主从同步问题

解决方案
  1. 延时删除
    更新完数据库后延时一段时间再进行删除,避免主从数据库同步延迟造成的数据不一致
  2. 订阅数据库binlog进行删除
    可以订阅数据库的binlog,等从数据库全部同步完成后再删除缓存
  3. 加锁
    更新数据库+删除缓存合并成一个原子操作,进行加锁处理,线程A进行更新时,加锁,线程B判断有锁后,直接读取数据库数据进行返回,不再进行写缓存操作
    在这里插入图片描述

总结

请添加图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值