缓存和数据库一致性问题分析

这篇具有很好参考价值的文章主要介绍了缓存和数据库一致性问题分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1、数据不一致的原因

1.1 并发操作

1.2 非原子操作

1.3 数据库主从同步延迟

2、数据不一致的解决方案

2.1 并发操作

2.2 非原子操作

2.3 主从同步延迟

2.4 最终方案

3、不同场景下的特殊考虑

3.1 读多写少的场景

3.2 读少写多的场景


1、数据不一致的原因

导致缓存和数据库数据不一致的原因有三个

  • 并发操作
  • 非原子操作
  • 数据库主从同步延迟

1.1 并发操作

假设数据库的原数据为x=0,考虑两种并发情况

  • 两个线程同时写入
  • 一个线程读,一个线程写

有以下4种方案

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

(1)先更新缓存,后更新数据库

两个线程同时写入

  • A更新缓存,x=1
  • B更新缓存,x=2
  • B更新数据库,x=2
  • A更新数据库,x=1

最终缓存为2,数据库为1

一个线程读,一个线程写

  • A读取缓存发现没有命中,于是读取数据库,得到x=0
  • B更新缓存,x=1
  • B更新数据库,x=1
  • A更新缓存,x=0

最终缓存为0,数据库为1

这种情况发生的概率极小,需要同时满足几个条件

  • 第一,缓存不存在
  • 第二,A的更新缓存命令 后于 B的更新缓存命令(基本不可能发生)
  • 第三,A读取数据库+更新缓存的时间 > B更新缓存+B更新数据库的时间(基本不可能发生,因为写数据库的耗时大概率是比读数据库慢)

(2)先更新数据库,后更新缓存

两个线程同时写入

  • A更新数据库,x=2
  • B更新数据库,x=1
  • B更新缓存,x=1
  • A更新缓存,x=2

最终缓存为2,数据库为1

一个线程读,一个线程写

  • A读取缓存发现没有命中,于是读取数据库,得到x=0
  • B更新数据库,x=1
  • B更新缓存,x=1
  • A更新缓存,x=0

最终缓存为0,数据库为1

这种情况发生的概率也是极小,跟方案2的发生条件一样。

(3)先删除缓存,再更新数据库

两个线程同时写入

由于是删除缓存,多线程同时更新的话,缓存都是会被删除,没有讨论意义

一个线程读,一个线程写

  • A读取缓存发现没有命中,于是读取数据库,得到x=0
  • B删除缓存
  • A更新缓存,x=0
  • B更新数据库,x=1

最终,缓存是0,数据库是1

(4)先更新数据库,再删除缓存

两个线程同时写入

由于是删除缓存,多线程同时更新的话,缓存都是会被删除,没有讨论意义

一个线程读,一个线程写

  • A读取缓存发现没有命中,于是读取数据库,得到x=0
  • B更新数据库,x=1
  • B删除缓存
  • A更新缓存,x=0

最终,缓存是0,数据库是1

这种情况发生的概率也是极小,需要同时满足几个条件

  • 第一,缓存不存在
  • 第二,B更新数据库+删除缓存的时间 < A读取数据库+更新缓存的时间 (基本不可能发生,因为写数据库的耗时大概率是比读数据库慢)

1.2 非原子操作

非原子操作很好理解,就是因为操作缓存和操作数据库是两步操作,所以当第二步操作失败时,就会导致数据不一致问题。

1.3 数据库主从同步延迟

以上都只考虑了单机数据库的情况,对于主从数据库还有另一个问题,就是主从同步延迟

考虑以下情况

一个往主库写入,一个从从库读取

  • A更新主库,x=1
  • A删除缓存
  • B查询缓存没有命中,查询从库,得到x=0
  • 从库同步主库,更新为x=1
  • B更新缓存,x=0

最终,缓存是0,数据库是1

2、数据不一致的解决方案

2.1 并发操作

根据1.1的几种方案,『先更新数据库,再删除缓存』是最好的。

2.2 非原子操作

最简单的解决办法就是重试,但是重试也要考虑一些问题:

  • 立即重试的话大概率会失败;
  • 重试次数设置多少比较合适;
  • 同步重试会一直占用资源;
  • 重试的过程中服务重启,会导致重试的操作消失,数据会一直不一致

所以就能想到异步重试方法,也就是把重试的这个操作写入到消息队列里,由另一个线程专门来处理重试的操作,而且消息队列本身可以保证消息不丢失(不丢失有两个方面,一是消息持久化,二是只有正确被消费掉了才会删除)

除了消息队列这中异步重试方案外,业界还有一种监听数据库bin log的方式,监听到变化后再去操作缓存,但是这种会额外引入其他的中间件而且实现复杂,综合而言没有消息队列的方案好用。

2.3 主从同步延迟

主从同步延迟的解决方案也很明显,就是延迟删除缓存,但是延迟多久再执行删除呢?这个就要靠经验了,一般来说1~5秒不等,看具体业务

所以在之前方案的基础上,引入延迟删除可以解决主从同步延迟的问题。

2.4 最终方案

1)更新数据库

2)删除缓存

3)如果删除失败则额外写入一条重试删除命令到消息队列

4)最后写入一个延迟删除命令到消息队列

3、不同场景下的特殊考虑

3.1 读多写少的场景

这种场景下,redis的作用是为了减轻数据库读取压力、加速读取,往往能接受一定的数据延迟,即保证最终一致性即可。

  • 读多,所以删除缓存操作会导致缓存穿透问题(key不存在,大量请求命中数据库)
  • 写少,所以基本不存在并发写入的问题,但是会存在并发读取和写入的问题

所以,读多写少的场景下,方案3和4是容易出现大问题的。

方案1和方案2是相对能接受的,但是也会有一定概率存在并发写入导致数据不一致的问题。

此时我们可以通过给缓存设置过期时间,使得数据保证最终一致性。

3.2 读少写多的场景

这种场景下,redis的作用是为了减轻数据库写入压力,对数据的一致性要求较高。

  • 读少,所以并发读取和写入的情况比较少
  • 写多,所以并发写入的情况比较多

由于并发写入情况比较多,此时方案3和4比较好,根据上文的分析,方案4比方案3更好。文章来源地址https://www.toymoban.com/news/detail-620793.html

到了这里,关于缓存和数据库一致性问题分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis 原理缓存过期、一致性hash、雪崩、穿透、并发、布隆、缓存更新策略、缓存数据库一致性

    redis的过期策略可以通过配置文件进行配置 redis会把设置了过期时间的key放在单独的字典中,定时遍历来删除到期的key。 1).每100ms从过期字典中 随机挑选20个,把其中过期的key删除; 2).如果过期的key占比超过1/4,重复步骤1 为了保证不会循环过度,导致卡顿,扫描时间上限

    2024年02月08日
    浏览(58)
  • redis实战-缓存数据&解决缓存与数据库数据一致性

    缓存( Cache),就是数据交换的 缓冲区 ,俗称的缓存就是 缓冲区内的数据 ,一般从数据库中获取,存储于本地代码。防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪,这在实际开发中对企业讲,对产品口碑,用户评价都是致命的;所以企业非常重视缓存技术,

    2024年02月12日
    浏览(55)
  • 如何保证缓存和数据库的数据一致性

    若数据库更新成功,删除缓存操作失败,则此后读到的都是缓存中过期的数据,造成不一致问题。 同删除缓存策略一样,若数据库更新成功缓存更新失败则会造成数据不一致问题。 若缓存更新成功数据库更新失败, 则此后读到的都是未持久化的数据。因为缓存中的数据是易

    2023年04月19日
    浏览(58)
  • 怎么保证缓存与数据库的最终一致性?

    目录 零.读数据的标准操作 一.Cache aside Patten--旁路模式 二.Read/Write Through Pattern--读写穿透 三.Write Back Pattern--写回 四.运用canal监听mysql的binlog实现缓存同步 这里想说的是不管哪种模式读操作都是一样的,这是一种统一的规范: 但写操作和同步策略却有不同。 这个是最常见的

    2024年04月08日
    浏览(47)
  • Redis如何保证缓存和数据库一致性?

    现在我们在面向增删改查开发时,数据库数据量大时或者对响应要求较快,我们就需要用到Redis来拿取数据。 Redis:是一种高性能的内存数据库,它将数据以键值对的形式存储在内存中,具有读写速度快、支持多种数据类型、原子性操作、丰富的特性等优势。 优势: 性能极高

    2024年01月16日
    浏览(70)
  • Redis---数据库和缓存如何保证一致性?

    用「读 + 写」请求的并发的场景来分析: 假如某个用户数据在缓存中不存在,请求 A 读取数据时从数据库中查询到年龄为 20,在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21,并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存

    2024年01月24日
    浏览(57)
  • 如何保证数据库和缓存双写一致性?

    如何保证数据库和缓存双写一致性,是面试中经常被问的一个技术问题,程序汪推荐大家有必要好好研究一波 数据库和缓存(比如:redis)双写数据一致性问题,是一个跟开发语言无关的公共问题。尤其在高并发的场景下,这个问题变得更加严重。 我很负责的告诉大家,该问

    2024年01月18日
    浏览(61)
  • Redis缓存MySQL数据库存储二者如何保证数据一致性

    在大型互联网应用中,由于数据库读写频繁、压力大等原因,我们通常会使用缓存来减少数据库的访问次数,提高系统的性能。而Redis作为一个高性能的内存数据库,成为了缓存的首选方案之一。但是,缓存和数据库之间存在数据一致性的问题,如何解决这个问题呢?本文将

    2023年04月19日
    浏览(52)
  • 如何保证缓存与数据库双写时的数据一致性?

    背景:使用到缓存,无论是本地内存做缓存还是使用 Redis 做缓存,那么就会存在数据同步的问题,因为配置信息缓存在内存中,而内存时无法感知到数据在数据库的修改。这样就会造成数据库中的数据与缓存中数据不一致的问题。 共有四种方案: 先更新数据库,后更新缓

    2024年01月24日
    浏览(47)
  • redis面试题目-如何保证数据库与缓存的数据一致性

    原视频:https://www.bilibili.com/video/BV1Km4y1r75f?p=62vd_source=fa75329ae3880aa55609265a0e9f5d34 由于缓存和数据库是分开的,无法做到原子性的同时进行数据修改,可能出现缓存更新失败,或者数据库更新失败的情况,这时候会出现数据不一致,影响前端业务 先更新数据库,再更新缓存。缓

    2024年02月05日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包