首页 > 数据库 >[Redis] 02-缓存和数据库数据一致性问题

[Redis] 02-缓存和数据库数据一致性问题

时间:2024-03-08 18:59:15浏览次数:28  
标签:02 缓存 删除 数据库 Redis 更新 并发 数据

经过一番排查,确认服务器的性能瓶颈是在数据库。给服务器加上Redis,让其作为数据库的缓存。
这样,在客户端请求数据时,如果能在缓存中命中数据,那就查询缓存,不用再去查询数据库,从而减轻数据库的压力,提高服务器的性能。

一、缓存模型

二、数据库和缓存的数据不一致问题

更新数据时,数据库的数据时客户端第二次更新操作的数据,而缓存确还是第一次更新操作的数据,也就是出现了数据库和缓存不一致的问题
造成缓存和数据库的数据不一致的现象,是因为并发问题

先更新数据库,还是先更新缓存?(并发双写,不使用该方案)

并发双写:在并发双写中,当数据更新时,会同时更新缓存和数据库,以确保它们保持一致。
尽管并发双写可以减少数据不一致性的可能性,但它并不能完全消除这种风险。

先更新数据库,再更新缓存:

先更新缓存,再更新数据库:

所以,无论是「先更新数据库,再更新缓存」,还是「先更新缓存,再更新数据库」,这两个方案都存在并发问题,当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象。

先更新数据库,还是先删除缓存?

不更新缓存,而是删除缓存中的数据。然后,到读取数据时,发现缓存中没了数据之后,再从数据库中读取数据,更新到缓存中。(即用删除缓存代替更新缓存)

写策略步骤:

  • 更新数据库中的数据
  • 删除缓存中的数据

读策略步骤:

  • 如果读取的数据命中了缓存,则直接返回数据
  • 如果读取的数据没有命中缓存,则从数据库中读取数据,然后将数据写入到缓存,并返回给用户

那问题又来了:在[写策略]的时候,到底选择哪种顺序呢?

  • 先删除Redis缓存中数据,再更新MySQL中的数据
  • 先更新MySQL中的数据,再删除Redis缓存中的数据

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

可以看到,先删除缓存,再更新数据库,在「读 + 写」并发的时候,还是会出现缓存和数据库的数据不一致的问题

解决方案:双删

双删的问题:
如果重建缓存的时间比较长,线程1删除Redis缓存后,线程2才重建完缓存,这时会出现数据不一致问题。

延迟双删:
第二次删除操作具体延迟多久呢?

大于线程2重建缓存的时间。

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

因为缓存的写入通常要远远快于数据库的写入,所以在实际中很难出现请求 B 已经更新了数据库并且删除了缓存,请求 A 才更新完缓存的情况。
而一旦请求 A 早于请求 B 删除缓存之前更新了缓存,那么接下来的请求就会因为缓存不命中而从数据库中重新读取数据,所以不会出现这种不一致的情况。
所以,「先更新数据库 + 再删除缓存」的方案,是可以保证数据一致性的。(也得承受几百毫秒的数据不一致性)

先删除缓存,数据不一致更加严重点。所以,我们一般选择使用后删除缓存。

但是后删除缓存也可能存在问题(当删除缓存失败的时候):
所以我们给key设置一个过期时间(兜底方案)。


最好的解决方案:

三、总结


标签:02,缓存,删除,数据库,Redis,更新,并发,数据
From: https://www.cnblogs.com/keyongkang/p/18061643

相关文章

  • P6810 「MCOI-02」Convex Hull 凸包 题解
    分析推式子题。\[ans=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\tau(i)\tau(j)\tau(\gcd(i,j))\]对于\((i,j)\),若\(k\)是\((i,j)\)的因子,则\(k\)一定整除\(i,j\),所以有:\[\\\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\tau(i)\tau(j)\sum\limits......
  • P9825 [ICPC2020 Shanghai R] Fibonacci
    原题链接题解直观的\(O(n)\)算法很容易想到,但是很不幸,挂了所以我们要想到\(O(1)\)的做法考虑到斐波那契数列非常有规律,所以我们找找规律奇,奇,偶,奇,奇,偶。。。code#include<bits/stdc++.h>usingnamespacestd;#definelllonglonglla[5]={0};intmain(){lln......
  • P9632 [ICPC2020 Nanjing R] K Co-prime Permutation
    原题链接题解我一开始也很困惑,然后我想要不数据范围小一点我构造看看当\(n=5\)时\(k=0\)可不可以\(k=1\)可不可以\(k=2\)可不可以然后根据直觉,\(gcd(a,a+1)\)始终为一,且一和任何数的最大公约数都为一,自己和自己的最大公约数还是自己,所以萌生了以下想法把一后面......
  • [Redis] 01-Redis快速入门
    一、Redis简介Redis属于键值对(key-value)数据库Redis中所有的数据都是以key-value的形式存储在内存中的所以读写Redis非常的快,在高并发的场景下,性能非常的好二、Redis服务端(redis-server)的安装省略。建议使用docker安装。Docker安装redis(保姆级教程&图文并茂)-腾讯......
  • C语言0基础入门游戏辅助开发—学习笔记02
    C语言0基础入门游戏辅助开发—学习笔记02PS:这里仅作为本人学习过程中的随笔。数据类型、sizeof运算符数据类型数据类型是在关键字内的,或者说关键字包含数据类型。数据类型有哪些程序中的代码和数据都是以二进制的形式存储的,对计算机系统和硬件而言,数据类型的概念不存在,这......
  • 使用 Visual Studio 2022 直接调试 WebAPI
    参考资料https://learn.microsoft.com/zh-cn/aspnet/core/test/http-files?view=aspnetcore-8.0在没有Postman等专门软件环境下,有没有轻量的调试http方法呢?尤其是每天都要打开宇宙第一IDE的环境,其实VS本身就带了一种方式,就是创建一个http文件来完成这个工作.VisualStud......
  • 2024-03-08 leetcode写题记录
    目录2024-03-08leetcode写题记录27.移除元素题目链接题意解法179.最大数题目链接题意解法75.颜色分类题目链接题意解法2024-03-08leetcode写题记录27.移除元素题目链接27.移除元素题意给你一个数组\(nums\)和一个值\(val\),你需要原地移除所有数值等于\(val\)的元素,并......
  • redis自学(13)阻塞IO与非阻塞IO
    阻塞IO顾名思义,阻塞IO就是两个阶段都必须阻塞等待:  调用revfrom函数的时候,内核没有数据,有两种处理结果,一个是返回失败的信息,一个是等待,而阻塞IO的选择是等待。可以看到,阻塞IO模型中,用户进程在两个阶段都是阻塞状态。非阻塞IO顾名思义,非阻塞IO的recvfrom操作会立即返回结......
  • 联合省选 2024
    D1T1考虑什么样的\(m\)是合法的,发现只需要\(|X-\sum_{i=0}^{m-1}x_i|+|Y-\sum_{i=0}^{m-1}y_i|\lemk\)。这里认为\(x,y\)以\(n\)为周期无限循环。把绝对值拆开,可以得到四个式子:\[\begin{cases}X+Y-\sum_{i=0}^{m-1}(x_i+y_i+k)\le0\\X-Y-\sum_{i=0}^{m-1}(x_i-y_......
  • 2024哈佛-麻省数学竞赛(HMMT)2月锦标赛 团体赛第9题
    [55](题目分数)在一个200*200的网格表的每个单元格上放置一辆汽车,它面向四个基本方向之一。在一步操作中,选择一辆前面没有汽车立即挡住的汽车,并将其向前滑动一个单元格。如果一步操作会导致汽车离开网格,则将该汽车移除。对初始放置方法的要求是,一定存在一系列操作,最终可以将所有汽......