浅析缓存一致性的解析方案

news2024/11/28 16:00:04

各位同学们平时开发的时候除了使用到数据库(这里以mysql为例)还会用到相关的缓存(这里以redis为例)操作。
举一个常用的场景当我们写的接口性能相对比较慢的时候(高并发场景需要响应速度很快)为了保证性能的达标,我们一般会结合用缓存来提高响应,比如redis号称每秒响应次数达到10W级。
那么问题来了,如何保证数据库和缓存的接口一致性呢,本文就来简要的分析一下目前市面上大家常用的6种不通的缓存一致性解决方式。
在这里插入图片描述

一、方案介绍

方案一、先写数据库,在写缓存

在这里插入图片描述

请求 A、B 都是先写数据库,然后再写缓存,在高并发情况下,如果请求 A 在写缓存时卡了一会,请求 B 已经依次完成数据的更新,就会出现图中的问题。
对于读请求,先去读缓存,如果没有,再去读 数据库,但是读请求不会再回写缓存。

方案二、先写缓存,再写数据库

在这里插入图片描述
方案二和方案一相反,先写缓存,在写数据库,

方案三、先删除缓存,再写数据库

在这里插入图片描述
这里的请求 A 是更新请求,但是请求 B 是读请求,且请求 B 的读请求会回写数据库。
请求 A 先删除缓存,可能因为卡顿,数据一直没有更新到数据库,导致两者数据不一致。这种情况出现的概率比较大,因为请求 A 更新数据库可能耗时会比较长,而请求 B 的前两步都是查询,会非常快。

方案四、先删除缓存,再写数据库,再删除缓存

对于“先删除缓存,再写 数据库”,如果要解决最后的不一致问题,其实再对 缓存重新删除即可,这个也是常说的“缓存双删”。
在这里插入图片描述
“删除缓存 5”必须在“回写缓存5”后面,怎么保证一定是在后面呢?
走异步串行化删除,在任务处理完成后把最后“删除缓存 5”放到异步队列中,进行延迟删除,确保最后的一致性。
在这里插入图片描述
异步删除对线上业务无影响,串行化处理保障并发情况下正确删除。
如果双删失败怎么办?建议走重试机制,方案一是借助消息队列的重试机制;方案二也可以自己整个表,记录重试次数。

方案五、先写数据库,再删除缓存

在这里插入图片描述
对于上面这种情况,对于第一次查询,请求 B 查询的数据是 5,但是 数据库中的数据是 6,只存在这一次不一致的情况,对于不是强一致性要求的业务,可以容忍。(那什么情况下不能容忍呢,比如秒杀业务、库存服务等。)

当请求 B 进行第二次查询时,因为没有命中缓存,会重新查一次数据库,然后再回写到缓存。
在这里插入图片描述
这里需要满足 2 个条件:

  • 缓存刚好自动失效;
  • 请求 B 从数据库查出 5,回写缓存的耗时,比请求 A 写数据库,并且删除缓存的还长。

对于第二个条件,我们都知道更新数据库肯定比查询耗时要长,所以出现这个情况的概率很小,同时满足上述条件的情况更小。

方案六、先写数据库,通过 Binlog,异步更新缓存

这种方案,主要是监听数据库(mysql)的 Binlog,然后通过异步的方式,将数据更新到缓存,这种方案有个前提,查询的请求,不会回写缓存。
在这里插入图片描述
这个方案,会保证数据库和缓存的最终一致性,但是如果中途请求 B 需要查询数据,如果缓存无数据,就直接查数据库;如果缓存有数据,查询的数据也会存在不一致的情况。

所以这个方案,是实现最终一致性的终极解决方案,但是不能保证实时性。

二、各方案的比较

方案一、先写数据库,在写缓存

  • 这种方案不建议用,万一数据库挂了,你把数据写到缓存,数据库无数据,影响肯定是灾难性的,如果真要使用,建议增加重试机制试试,如果操作失败的话;

方案二、先写缓存,再写数据库

  • 这种只适合那种并发量、一致性要求不高的项目,比如那种政企项目,之前做过的政企项目就是经常这么搞,但是不建议这么做;
  • 当缓存瞬间不可用的情况,需要及时告警,做后续处理。

方案三、先删除缓存,再写数据库

  • 这种方法……好像没使用过,一般都是用方案五。

方案四、先删除缓存,再写数据库,再删除缓存

  • 这种方式虽然可行,但是有点负责化了,还要搞个消息队列去异步删除 Redis。简单点的可以用java的异步线程去做延时删除。

方案五、先写数据库,再删除缓存

  • 比较推荐这种方式,删除 Redis 如果失败,可以再多重试几次,否则报警出来;
  • 这个方案,是实时性中最好的方案,在一些高并发场景中,推荐这种。

方案六、先写数据库,通过 Binlog,异步更新缓存

  • 对于异地容灾、数据汇总等,建议会用这种方式,比如 binlog + kafka,数据的一致性也可以达到秒级;
  • 纯粹的高并发场景,不建议用这种方案,比如抢购、秒杀等。

三、总结

  • 实时一致性方案:采用“先写数据库,再删除缓存”的策略,这种情况虽然也会存在两者不一致,但是需要满足的条件有点苛刻,所以是满足实时性条件下,能尽量满足一致性的最优解。
  • 最终一致性方案:采用“先写数据库,通过Binlog,异步更新缓存”,可以通过 Binlog,结合消息队列异步更新缓存,是最终一致性的最优解。

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

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

相关文章

LeetCode144. 二叉树的前序遍历

144. 二叉树的前序遍历 文章目录 [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/)一、题目二、思路及代码(1)递归(2)迭代(两种方法) 一、题目 给你二叉树的根节点…

AlienSwap 首期 Launchpad — 偶像女团 NFT+RWA 的创新探索

NFT 是整个加密市场一致看好,并认为会继续爆发的领域。随着更多的 NFT 平台和 NFT 项目的推出,NFT 市场的格局也在不断变化。从开始的 OpenSea 占据绝对领先地位,到 Blur 的横空出世风头无两,在加密领域,局势更迭总是在…

【Java面试丨并发编程】线程中并发安全

一、Synchronized关键字的底层原理 1. Synchronized的作用 Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其他线程再想获取这个【对象锁】时就会阻塞住 2. Monitor Synchronized【对象锁】底层是由Monitor实现,…

泰裤辣!这是什么操作,自动埋点,还能传参?

目录 前言 参数放在注释中 准备入口文件 编写插件 运行代码 完整代码 参数放在局部作用域中 准备源代码 编写插件 运行代码 完整代码 总结 前言 在上篇文章讲了如何通过手写babel插件自动给函数埋点之后,就有同学问我,自动插入埋点的函数怎么…

基于IMX6ULL的AP3216C的QT动态数据曲线图显示

前言:本文为手把手教学 LinuxQT 的典型基础项目 AP3216C 的数据折线图显示,项目使用正点原子的 IMX6ULL 阿尔法( Cortex-A7 系列)开发板。项目需要实现 AP3216C 在 Linux 系统下的驱动,使用 QT 设计 AP3216C 的数据显示页面作为项目的应用层。…

消息中间件RabbitMQ简介

1.1消息队列中间件简介 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题实现高性能,高可用,可伸缩和最终一致性[架构] 使用较多的消息队列有ActiveMQ,RabbitMQ&#xff…

人工智能安全风险:零信任的作用

人工智能(AI)和机器学习技术飞速发展,我们所处的时代正在经历前所未有的创新。但是,技术飞速发展的同时也带来了各种挑战。人工智能技术越来越复杂,与之相关的网络安全风险也越来越棘手,随之产生了一个新的…

TortoiseGit 入门指南10:贮藏

有时,当你在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状态, 而这时你想要切换到另一个分支做一点别的事情。 问题是,你不想仅仅因为过会儿回到这一点而为做了一半的工作创建一次提交。 针对这个问题的答案是贮藏 …

【Linux指令集】---unzip指令(超详细)

个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【Linux专栏】🎈 本专栏旨在分享学习Linux的一点学习心得,欢迎大家在评论区讨论💌 演示环境&#xff1…

JVM系统优化实践(19):GC生产环境案例(二)

您好,这里是「码农镖局」CSDN博客,欢迎您来,欢迎您再来~ 接昨天的问题继续来说,在高并发场景中,对象过多容易导致OOM。由于高并发导致Young GC存活对象过多,因此会有太多对象进入老年代&#xf…

关于unity Content Size Fitter 套 Content Size Fitter

首先:最好不要unity Content Size Fitter 套 Content Size Fitter 这样最后得到的变化可能会错误 unity也提示了,父物体如果有了,那么子物体就不要再加了。 但是你们要的需求: 一级父物体 ➡自适应大小➡二级父物体&#xff08…

经典目标检测R-CNN系列(2)Fast R-CNN

经典目标检测R-CNN系列(2)Fast R-CNN Fast R-CNN是作者Ross Girshick继R-CNN后的又一力作。 同样使用VGG16作为网络的backbone,与R-CNN相比训练时间快9倍,测试推理时间快213倍,准确率从62%提升至66%(Pascal VOC数据集上)。 1 Fast R-CNN的…

Java List 与数组互转

前言 略 数组转 List 方法1 Employee[] array new Employee[]{emp1, emp2, emp3}; List<Employee> list Arrays.asList(array);Arrays.asList 返回的是固定长度的数组&#xff0c;扩大或缩小列表的操作将返回UnsupportedOperationException。 数组转 List 方法2 E…

【C++STL】“vector“容器的模拟实现

vector的模拟实现 模拟实现成员变量构造函数无参构造函数初始化n个val的构造函数迭代器区间构造函数 拷贝构造析构函数begin&#xff08;&#xff09;end&#xff08;&#xff09;swap&#xff08;&#xff09;reserve()resize()capacity()size()重载[]运算符重载赋值运算符ins…

自学网络安全(黑客)为什么火了?

网安专业从始至终都是需要学习的&#xff0c;大学是无法培养出合格的网安人才的。这就是为啥每年网安专业毕业生并不少&#xff0c;而真正从事网安岗位的人&#xff0c;寥寥无几的根本原因。 如果将来打算从事网安岗位&#xff0c;那么不断学习是你唯一的途径。 网络安全为什…

应对 618、双十一等大促期间的高负载,API 性能测试应该怎么做?负载测试、基线测试、冒烟测试、浸泡测试、峰值测试和尖峰测试详解

随着应用程序和服务交付速度的不断提高&#xff0c;在按时交付应用程序的竞赛中&#xff0c;性能测试往往会退居其次。但是&#xff0c;在节假日期间&#xff0c;购物额都会大幅增长。在这种一年中的成败时刻&#xff0c;公司是无法接受他们的应用程序在高负载下变得不可靠的。…

第四章 云原生架构之Kubernetes基础知识

1、K8S整体架构 1.1、概述 ​ Kubernetes是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;简称 K8S。K8S的本质是一组服务器集群&#xff0c;可以在对应服务器集群的每个节点上运行程序&#xff0c;来对节点中的容器进行管理。类似Mas…

Pytest+Jenkins+Allure的接口自动化测试

目录 生成Allure 两种形式 一 项目内直接生成不依赖Jenkins 1.先安装好allure 将allure\bin配置到环境变量中 cmd 命令行输入&#xff1a;allure 校验是否安装成功 2. 将json文件生成html文件 执行 allure generate report/ -o report/html其中的report/ 为生成的json路径&a…

OCPM和CPM有什么区别?

CPM和OCPM这两种收费模式的对比 Cpm&#xff1a;表示千次展示费用&#xff0c;是数据指标&#xff0c;也是一种出价方式。代表展现一千次的消费&#xff0c;也就是你展现1000次要给媒体多少钱 例如某企业广告曝光量是50万&#xff0c;总广告价格为10000元&#xff0c;那么千人…

matplotlib 笔记:marker 款式

1 ec 边缘颜色 marker 边缘的颜色 import numpy as np import matplotlib.pyplot as pltxnp.linspace(0,10) ynp.sin(x)1.5 plt.figure(figsize(10,10)) plt.scatter(x,y,ecC9) plt.show() 2 fc 填充颜色 face color 填充颜色 3 lw 边缘宽度 4 s 点的大小 5 marker 点款式 i…