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 时序图

相关推荐
尘浮生5 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
六月闻君18 分钟前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
SelectDB技术团队27 分钟前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
郑祎亦28 分钟前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
本当迷ya41 分钟前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
inventecsh43 分钟前
mongodb基础操作
数据库·mongodb
白云如幻1 小时前
SQL99版链接查询语法
数据库·sql·mysql
爱吃烤鸡翅的酸菜鱼1 小时前
MySQL初学之旅(4)表的设计
数据库·sql·mysql·database
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
paopaokaka_luck2 小时前
[371]基于springboot的高校实习管理系统
java·spring boot·后端