Redis和数据库的一致性问题

一致性

一致性简单的理解是在完成一系列的动作之后,最后得到的结果要与我们的预期一致。在分布式系统中,可以理解为多个节点的数据保持一致。

一致性可以分为以下几类:

  1. 强一致性:强一致性需要保证用户输入的是什么,读出来的就是什么,对于用户来说体验很好,但是可能会影响系统的性能。
  2. 弱一致性:弱一致性就比较随意了。它不承诺用户能够立即读到数据,也不承诺在什么时间内完成数据一致,只是尽可能在较短的时间内使数据一致。
  3. 最终一致性:最终一致性是弱一致性的一种特殊情况,可以保证在一定时间内完成数据一致性。这种方式在分布式系统中应用极为广泛,mysql的日志、MQ、redis等都有应用。

Redis中的一致性

在项目中同时使用mysql和redis作为缓解数据库压力的一种解决方式时,mysql和redis的数据一致性是不可忽视的,数据库和缓存的数据同步可以分为以下两种类型:

  • 更新缓存类
    • 先更新数据库再更新缓存
    • 先更新缓存再更新数据库

更新缓存类的方案是不适合使用的,因为在大量请求访问时会有很大概率出现数据不一致和脏读的情况,如图:

脏读(情况1):更新数据库速度较慢,会有很多请求读取的是缓存中的旧数据;

数据不一致(情况2):更新缓存很容易因为各种原因出现数据不一致的情况,而且难以察觉,因为缓存中的数据一直都存在;

  • 删除缓存类
    • 先删除缓存再更新数据库
    • 先更新数据库再更新缓存

更新缓存类相比删除缓存类存在的弊端:

  1. 如果存在复杂计算后存入缓存的情况,频繁更新缓存浪费较多性能;
  2. 读少写多的情况下,还没开始读,数据被更新好多次了,浪费性能。

删除缓存的两种类型中需要考虑是先删除缓存还是先更新数据库,如图两种情况进行分析:

先更新数据库(情况3):这种情况可能会出现脏读,但是几率比较小。因为读取数据库到更新缓存的时间肯定远小于更新数据库的时间;

先删除缓存(情况4):这种情况就是删除缓存之后在缓存中读不到会直接读数据库,在并发条件下使得缓存和数据库不一致,并且更新数据库相对数据读取来说速度更慢,这样数据库压力会变大;

解决方案

针对情况4的解决方案:

情况4中可能会出现缓存和数据库不一致的情况,为了解决这种问题,最简单的解决方法就是使用延时双删策略。

延时双删

在删除缓存->更新数据库之后的一段时间 内再次删除缓存,这一段时间一般是执行业务的时间加上几百毫秒,方便业务执行完成后有时间进行缓存删除。

针对情况3的解决方案:

情况3中虽然出现脏数据的概率很小,但是也不是没有办法解决,首先想到就是使用缓存的过期 机制,或者使用异步删除缓存 方式。但是这两种方式还有一个问题:如果更新数据库成功了,删除缓存失败了,这样就会有很多请求从缓存中查出旧的数据。为了解决这个问题可以考虑使用删除补偿的方式。

使用MQ进行补偿

在删除缓存时将删除失败的记录放到消息队列中,通过消费者消费再次进行删除。

直接使用MQ进行补偿的方式有一个缺点,需要在代码中判断是否需要入队,这样和业务代码耦合较大,这个问题可以使用cancel订阅binlog日志的方式解决。

订阅binlog日志

使用cancel监控binlog日志的变化,将变化消息存入消息队列中,通过消息队列进行消费加以补偿。

逻辑流程如图所示:

缓存更新的设计模式

Cache Aside

这种设置模式是最常见的模式,它先从缓存中读取数据,读取不到再去数据库中读取,然后更新缓存。

Read\Write Through

这种模式其实是对Cache Aside的封装,中间加了一层缓存抽象层,使得对数据库的操作由缓存代理,大大减少了的步骤,不然需要同时处理缓存和数据库。这样对客户端来说,就只关心缓存这一层就够了。

Read Through 时序图

Write Through 时序图

相关推荐
麦聪聊数据10 分钟前
企业数据市场建设(四):流程闭环与价值运营,让数据市场真正转起来
运维·数据库
正儿八经的少年16 分钟前
redis 的大 key 和热 key 详解
数据库·redis·缓存
AI砖家20 分钟前
多智能体系统实战:架构设计、数据库表设计与 Skill 体系
数据库·多智能体·skill·agent架构设计·agengt
止语Lab41 分钟前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活41 分钟前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
夜雪一千1 小时前
MySQL查询条件的顺序是否影响查询效率
数据库·mysql
用户298698530141 小时前
Python 实现 Excel 与 Markdown 互转的实用指南
后端·python·excel
用户77283104908401 小时前
krono-job:零侵入、单二进制交付的分布式任务调度平台(开源)
后端