Redis缓存(双写一致性问题)

news2024/11/24 23:03:28

Redis缓存(双写一致性问题)

  • 1 什么是缓存?
    • 1.1 为什么要使用缓存
    • 1.2 如何使用缓存
  • 2 添加缓存
    • 2.1 、缓存模型和思路
    • 2.2、代码如下
  • 3 缓存更新策略
    • 3.1 、数据库缓存不一致解决方案:
    • 3.2 、数据库和缓存不一致采用什么方案
  • 4 实现商铺和缓存与数据库双写一致
  • 5 双写一致性改进:延时双删

1 什么是缓存?

前言:什么是缓存?

缓存就像自行车,越野车的避震器
举个例子:越野车,山地自行车,都拥有"避震器",防止车体加速后因惯性,在酷似"U"字母的地形上飞跃,硬着陆导致的损害,像个弹簧一样;

同样,实际开发中,系统也需要"避震器",防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪;

这在实际开发中对企业讲,对产品口碑,用户评价都是致命的;所以企业非常重视缓存技术;

缓存(Cache),就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码(例如:

1:Static final ConcurrentHashMap<K,V> map = new ConcurrentHashMap<>(); 本地用于高并发

例2:static final Cache<K,V> USER_CACHE = CacheBuilder.newBuilder().build(); 用于redis等缓存

例3:Static final Map<K,V> map =  new HashMap(); 本地缓存

由于其被Static修饰,所以随着类的加载而被加载到内存之中,作为本地缓存,由于其又被final修饰,所以其引用(例3:map)和对象(例3:new HashMap())之间的关系是固定的,不能改变,因此不用担心赋值(=)导致缓存失效;

1.1 为什么要使用缓存

一句话:因为速度快,好用

缓存数据存储于代码中,而代码运行在内存中,内存的读写性能远高于磁盘,缓存可以大大降低用户访问并发量带来的服务器读写压力

实际开发过程中,企业的数据量,少则几十万,多则几千万,这么大数据量,如果没有缓存来作为"避震器",系统是几乎撑不住的,所以企业会大量运用到缓存技术;

但是缓存也会增加代码复杂度和运营的成本:

在这里插入图片描述

1.2 如何使用缓存

实际开发中,会构筑多级缓存来使系统运行速度进一步提升,例如:本地缓存与redis中的缓存并发使用

浏览器缓存:主要是存在于浏览器端的缓存

**应用层缓存:**可以分为tomcat本地缓存,比如之前提到的map,或者是使用redis作为缓存

**数据库缓存:**在数据库中有一片空间是 buffer pool,增改查数据都会先加载到mysql的缓存中

**CPU缓存:**当代计算机最大的问题是 cpu性能提升了,但内存读写速度没有跟上,所以为了适应当下的情况,增加了cpu的L1,L2,L3级的缓存

在这里插入图片描述

2 添加缓存

假设有个外卖项目,在我们查询商户信息时,我们是直接操作从数据库中去进行查询的,大致逻辑是这样,直接查询数据库那肯定慢咯,所以我们需要增加缓存

@GetMapping("/{id}")
public Result queryShopById(@PathVariable("id") Long id) {
    //这里是直接查询数据库
    return shopService.queryById(id);
}

2.1 、缓存模型和思路

标准的操作方式就是查询数据库之前先查询缓存,如果缓存数据存在,则直接从缓存中返回,如果缓存数据不存在,再查询数据库,然后将数据存入redis。

在这里插入图片描述

2.2、代码如下

代码思路:如果缓存有,则直接返回,如果缓存不存在,则查询数据库,然后存入redis。

在这里插入图片描述

3 缓存更新策略

缓存更新是redis为了节约内存而设计出来的一个东西,主要是因为内存数据宝贵,当我们向redis插入太多数据,此时就可能会导致缓存中的数据过多,所以redis会对部分数据进行更新,或者把他叫为淘汰更合适

**内存淘汰:**redis自动进行,当redis内存达到咱们设定的max-memery的时候,会自动触发淘汰机制,淘汰掉一些不重要的数据(可以自己设置策略方式)

**超时剔除:**当我们给redis设置了过期时间ttl之后,redis会将超时的数据进行删除,方便咱们继续使用缓存

**主动更新:**我们可以手动调用方法把缓存删掉,通常用于解决缓存和数据库不一致问题

在这里插入图片描述

3.1 、数据库缓存不一致解决方案:

由于我们的缓存的数据源来自于数据库,而数据库的数据是会发生变化的,因此,如果当数据库中数据发生变化,而缓存却没有同步,此时就会有一致性问题存在,其后果是:

用户使用缓存中的过时数据,就会产生类似多线程数据安全问题,从而影响业务,产品口碑等;怎么解决呢?有如下几种方案

Cache Aside Pattern 人工编码方式:缓存调用者在更新完数据库后再去更新缓存,也称之为双写方案

Read/Write Through Pattern : 由系统本身完成,数据库与缓存的问题交由系统本身去处理

Write Behind Caching Pattern :调用者只操作缓存,其他线程去异步处理数据库,实现最终一致

在这里插入图片描述

3.2 、数据库和缓存不一致采用什么方案

综合考虑使用方案一,但是方案一调用者如何处理呢?这里有几个问题

操作缓存和数据库时有三个问题需要考虑:

如果采用第一个方案,那么假设我们每次操作数据库后,都操作缓存,但是中间如果没有人查询,那么这个更新动作实际上只有最后一次生效,中间的更新动作意义并不大,我们可以把缓存删除,等待再次查询时,将缓存中的数据加载出来

  • 删除缓存还是更新缓存?

    • 更新缓存:每次更新数据库都更新缓存,无效写操作较多
    • 删除缓存:更新数据库时让缓存失效,查询时再更新缓存
  • 如何保证缓存与数据库的操作的同时成功或失败?

    • 单体系统,将缓存与数据库操作放在一个事务
    • 分布式系统,利用TCC等分布式事务方案

应该具体操作缓存还是操作数据库,我们应当是先操作数据库,再删除缓存,原因在于,如果你选择第一种方案,在两个线程并发来访问时,假设线程1先来,他先把缓存删了,此时线程2过来,他查询缓存数据并不存在,此时他写入缓存,当他写入缓存后,线程1再执行更新动作时,实际上写入的就是旧的数据,新的数据被旧数据覆盖了。

  • 先操作缓存还是先操作数据库?
    • 先删除缓存,再操作数据库
    • 先操作数据库,再删除缓存

在这里插入图片描述

4 实现商铺和缓存与数据库双写一致

核心思路如下:

修改ShopController中的业务逻辑,满足下面的需求:

根据id查询店铺时,如果缓存未命中,则查询数据库,将数据库结果写入缓存,并设置超时时间

根据id修改店铺时,先修改数据库,再删除缓存

修改重点代码1:修改ShopServiceImpl的queryById方法

设置redis缓存时添加过期时间

在这里插入图片描述

修改重点代码2

代码分析:通过之前的淘汰,我们确定了采用删除策略,来解决双写问题,当我们修改了数据之后,然后把缓存中的数据进行删除,查询时发现缓存中没有数据,则会从mysql中加载最新的数据,从而避免数据库和缓存不一致的问题

在这里插入图片描述

5 双写一致性改进:延时双删

其实先更新数据库,后删除缓存这种方案也存在缺陷,即在删除缓存前另一个线程查询获取旧缓存。那么为了降低这种几率,我们可以将更新数据库和删除旧缓存之间的这段时间延长,使得另一个线程把旧的数据更新到缓存之后,才将缓存删除,这就保证了其他线程进来查询时的数据一致。

假设有A、B、C三个事务(线程),如下图:
在这里插入图片描述

显然,以上延时双删的方法仍然有一些局限性。其一,在a时间段内,也就是缓存仍为旧数据且来不及删除就缓存事件内,仍然会有事务查询得到就缓存,存在若干次脏数据;其二,b时间段内,我们可以尽可能缩短b时间段,以保证A事务尽快更新完数据库后,B事务查询数据库能拿到真数据。

总结
以上解决方案适用于对数据一致性比较大、请求量不是特别高的业务场景下。若是在高并发和查询数据量比较大的情况下 ,对若干次数据一致性要求不高,更需要提高缓存的命中率,这就使得第一次删除缓存的必要性降低,因为我们引入缓存的目的是降低数据库压力,如果因为一些不必要的第一次删除而降低了缓存的命中率,在高并发场景下显然会对数据库带来大的压力。当然第一次删除在情况一也有其带来数据一致的好处,只看我们的业务场景下是否需要牺牲部分数据一致的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480770.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C生万物】 指针篇 (初级)

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《C生万物 | 先来学C》&#x1f448; 前言&#xff1a; 面对C语言&#xff0c;很多童鞋都会高呼&#xff1a;指针难&#xff0c;指针难&#x…

【计算机专业漫谈】【计算机系统基础学习笔记】W2-1十进制数与二进制数,各进制数直接的转换

利用空档期时间学习一下计算机系统基础&#xff0c;以前对这些知识只停留在应试层面&#xff0c;今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC&#xff0c;参考书籍也是袁老师的教材&#xff0c;这是我的听课自查资料整理后的笔记 W2-1十进制…

ChatGPT背后的技术:人类反馈强化学习RLHF

文章目录 前言Chat GPT是如何基于RLHF进行训练的RLHF 技术分解预训练语言模型训练奖励模型强化学习微调预训练模型 局限性参考 前言 随着OpenAI推出的Chat GPT火热出圈&#xff0c;Chat GPT背后的技术原理之一&#xff0c;人类反馈强化学习RLHF (Reinforcement Learning from …

Matplotlib 网格线

我们可以使用 pyplot 中的 grid() 方法来设置图表中的网格线。 grid() 方法语法格式如下&#xff1a; matplotlib.pyplot.grid(bNone, whichmajor, axisboth, ) 参数说明&#xff1a; b&#xff1a;可选&#xff0c;默认为 None&#xff0c;可以设置布尔值&#xff0c;true…

prometheus实战之二:使用常见指标

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《prometheus实战》系列的第二篇&#xff0c;在《prometheus实战之一&#xff1a;用ansible部署》一文咱们部署了prometheus服务&#xff0c…

防护服穿戴检测识别算法 yolov8

防护服穿戴检测识别系统基于yolov8网络模型图片数据识别训练&#xff0c;算法模型自动完成对现场人员是否按照要求穿戴行为实时分析。YOLOv8 算法的核心特性和改动可以归结为如下&#xff1a;提供了一个全新的 SOTA 模型&#xff0c;包括 P5 640 和 P6 1280 分辨率的目标检测网…

【开发工具】 我居然可以使用Office Tool Plus 安装上Office 真的是太不可思议了

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

【开发工具】 Office Tool Plus 居然也可以部署 Office 365 我的天 真的是太厉害了

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

人不成熟的五大特征-读后感

原文地址&#xff1a;人不成熟的五大特征-百度经验 1 立即要回报 1 所有简单的快的&#xff0c;别人也能做&#xff0c;这并不能使你超过别人。 2 做出别人做不出来的复杂成果&#xff0c;需要较长的时间和持续的学习&#xff0c;得到就得付出&#xff0c;时间&#xff0c;资源…

Windows10本地搭建网站教程 - 内网穿透发布公网访问

文章目录 概述1. 搭建一个静态Web站点2. 本地浏览测试站点是否正常3. 本地站点发布公网可访问3.1 安装cpolar内网穿透3.2 创建隧道映射公网地址3.3 获取公网URL地址 4. 公网远程访问内网web站点5. 配置固定二级子域名5.1 保留二级子域名5.2 配置二级子域名 6. 测试访问二级子域…

【Java笔试强训 30】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;最难的问…

家乡特色推荐系统~java~mysql

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括家乡特色推荐的网络应用&#xff0c;在外国家乡特色推荐系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。家乡特色推荐系统采用java技术&…

常用半导体器件

&#xff08;1&#xff09;N 型半导体 在纯净的半导体硅或锗中掺入适量的五价磷元素&#xff0c;可形成带负电 的自由电子&#xff08;又称多数载流子&#xff09;参与导电。 &#xff08;2&#xff09;P 型半导体 在纯净的半导体硅或锗中掺入适量的三价硼元素&#xff0c;可形…

JavaEE初阶 - 文件/IO

一、认识文件 我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进行数据保存时&#xff0c;往往不是保存成一个整体&#xff0c;而是独立成一个个的单位进行保存&#xff0c;这个独立的单位就被抽象成文件的概念&#xff0c;就类似办公…

Docker持久化固定容器IP

基于Docker引擎创建Docker容器&#xff0c;在默认条件下创建容器是bridge桥接模式&#xff0c;启动容器IP地址是DHCP随机分配并且递增的&#xff0c;而且容器之间可以互相通信&#xff0c;网段也是固定的。 当Docker容器一旦关闭再次启动&#xff0c;就会导致容器的IP地址再次重…

C#,生信软件实践(01)——序列文件(如FASTA)合并工具的源代码

1 生物信息学简介 生物信息学&#xff08;BioInformatics&#xff09;是研究生物信息的采集、处理、存储、传播&#xff0c;分析和解释等各方面的学科&#xff0c;也是随着生命科学和计算机科学的迅猛发展&#xff0c;生命科学和计算机科学相结合形成的一门新学科。它通过综合…

Photoshop如何使用通道之实例演示?

文章目录 0.引言1.利用通道调整图像的颜色2.给风景照替换天空3.制作故障艺术效果4.使用通道抠取复杂图像 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对PS进行了学习&#xff0c;本文通过《Photoshop2021入门教程》及其配套素材结合网上相关资料进行学习笔记总结&a…

Linux命令集

一、Linux常用的目录处理命令集 1、ls命令&#xff08;用来查看目录和文件&#xff09; &#xff08;1&#xff09;ls -a&#xff08;查看所有文件包括隐藏文件&#xff09; &#xff08;2&#xff09;ls -l &#xff08;以长格式显示目录下的内容列表&#xff09; &#xff0…

【小样本分割 2022 ECCV】DCAMA

文章目录 【小样本分割 2022 ECCV】DCAMA摘要1. 简介2. 网络2.1 整体架构2.2 特征提取与掩模制备2.3 多尺度多层交叉注意加权掩码聚合。2.4 掩码特性混合器。 3. 代码 【小样本分割 2022 ECCV】DCAMA 论文题目&#xff1a;Dense Cross-Query-and-Support Attention Weighted Ma…

【分布式】路由配置服务

在之前我们将路由表以及分组信息一直存储在网关中&#xff0c;如下图&#xff1a; 显然这样设计并不合理&#xff1a; 网关应该只负责对用户的信息进行解析并根据类型进行转发&#xff0c;最大限度减少其他的负荷网关作为一个单点&#xff0c;在出现故障后&#xff0c;我们希…