缓存的使用及常见问题的解决方案

用户通过浏览器向我们发送请求,这个时候浏览器就会建立一个缓存,主要缓存一些静态资源(js、css、图片),这样做可以降低之后访问的网络延迟。然后我们可以在Tomcat里面添加一些应用缓存,将一些从数据库查询到的数据放到缓存里面,下次的查询可以直接从缓存里面拿,这样做的目的可以减少数据库查询,提高查询效率。数据库里面的索引数据也可以缓存起来,当我们根据索引查询数据时可以在内存里面快速检索,不用每次都读取磁盘,提高了查询效率。数据库做一些排序或者表关联的话会使用cpu做运算。这时候就会用到cpu的多级缓存。一个web应用的任何环节都可以添加缓存,但是这个缓存不能滥用。缓存是一把双刃剑。

缓存的作用:

降低后端负载:对于不使用缓存的查询业务,每次请求都会从数据库(磁盘)里面查询数据在响应到前端,这一过程比较缓慢,而且对数据库压力比较大。使用缓存之后,请求之后,可以在Tomcat缓存里面直接拿去数据,响应比较迅速,而且降低了数据库的压力。

提高读写速率、降低响应时间:缓存一般通过Redis实现,Redis的读写效率非常高(微秒级别)。

缓存的成本:

数据一致性成本:数据本来是存储在数据库里面,将其缓存了一份放到内存里面,用户查询的时候可以查询内存(使用Redis)虽然减轻了数据库压力,但是如果数据库的数据发生改变。如果Redis还是旧的数据

代码维护成本:为了解决数据一致性的问题,给我们代码的维护成本带来了一定问题。会有很多复杂的业务代码。在数据一致性处理的过程中还会碰到缓存穿透、击穿等问题也会增加代码成本。

运维成本:为了避免缓存雪崩的问题、保证缓存高可用,缓存一般搭建集群的模式会增加运维成本

2.添加Redis缓存

缓存工作的模型:

未添加缓存的web应用,客户端发送的请求会直接从数据库查询,拿到数据库数据之后,再返回给客户端。

添加缓存的web应用,客户端的请求会先到我们Redis,如果Redis有我们需要的数据,就会直接返回给客户端,不会使用数据库,数据库的压力就会减轻。如果没有我们需要的数据(请求未命中)才会使用数据库,数据库将数据返回给我们客户端。未命中的话还会将数据添加到缓存里面,提高缓存的命中率。

这是一个查询商铺的缓存流程:

首先前端会提高一个商铺的id,然后从Redis里面查询商铺,判断是否查询到(判断是否命中),如果命中就返回商铺的信息,如果未命中我们会去查询数据库,假如数据库不存在就返回404,假如数据存在,我们会先将这个数据写入Redis,然后返回商铺信息。

3.缓存更新策略

内存淘汰:

不用自己维护,利用Redis的内存淘汰机制,当内存不足的时候自动淘汰部分数据下次查询更新缓存。可以在一定程度上保证数据一致性,如果需要更新的数据被淘汰,下次通过数据库查询,又会被重新写入Redis从而保证数据一致性,但是内存淘汰不能被我们控制,淘汰数据不确定,所以一致性差,但维护成本低。

超时剔除:

给缓存数据添加TTL时间,到期后自动删除缓存,下次查询时跟新缓存。这种方式的一致性跟TTL设置的时间有关,时间越短一致性越高,这种一致性我们是可以控制的。但是数据库在我们设置的时间内发生改变的话数据还是会不一致,所以这种方式一致性一般,维护成本也很低。

主动更新:

编写业务逻辑,在修改数据库的同时,更新缓存。这种数据一致性比较好,但是维护成本很高。我们在写数据的crud的时候还得对缓存进行更新。

具体应该选择哪一种策略,需要考虑业务的场景:

低一致性需求:使用内存淘汰机制,例如店铺类型的查询缓存。

高一致性需求:主动更新,并以超时剔除作为兜底方案。例如店铺详情查询的缓存。

主动更新的三种实现方式:

01:人工编码的方式,通过自己的代码来实现数据更新之后更新缓存。

02:缓存与数据库整合为一个服务,由服务来维护一致性,调用者调用该服务,无需关心缓存一致性。这种服务维护成本比较高,开发难度大。

03:写回:调用者只操作缓存,由其它线程异步的将缓存数据持久化到数据库,保证最终的一致,就是crud直接对缓存操作,异步线程定期将缓存的数据对数据库进行更新。如果宕机数据就丢失了。

在日常的开发者我们通常使用方法01,这种方法的可控性最高,那我们通过这种方式实现数据一致性,需要考虑三个问题

问题一:删除缓存还是更新缓存?

更新缓存:每次更新数据库的操作同时更新缓存,无效写操作较多

删除缓存:更新数据库时让缓存失效,查询时再更新缓存

显然采用删除缓存比较合适

问题二:如何保证缓存与数据库的操作的同时成功与失败(保证原子性 )?

单体系统,将缓存与数据库操作放在一个事务

分布式系统,利用TCC等分布式事务方案

问题三:先操作缓存还是先操作数据库?

涉及到线程安全问题:

先删除缓存,再操作数据库(在不加锁的情况下)

异常情况:可能性较高(数据库操作时间相对与缓存读写比较长,这种异常概率较大)

在先删除缓存,再操作数据库过程中间,有别的线程查询操作,此时请求未命中,查询数据库,然而数据库还没有完成更新操作,查询的还是旧的数据,旧数据又被写入缓存。

先操作数据库,再删除缓存

异常情况:可能性较小(缓存的写入很快,数据库操作比较慢,这种异常情况发生概率较低)

在线程一查询的时候如果缓存失效,请求未命中,查询数据库,如何此时另一个线程删除缓存,之后线程一将查询的旧数据写入到缓存。

综上所述:选择方案二比较靠谱,即:先操作数据库,再删除缓存

4.缓存穿透

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。

危害:

正因为数据不存在,所以就不会建立缓存,所有的请求都会直接查询数据库,如果被攻击者通过并行的方式不断请求这个不存在的数据很可能我们的数据库就会崩溃。这就是缓存穿透的危害。

常见解决缓存穿透的方案:

缓存空对象:

如果数据库查询不到,就将这个控制存储到缓存里面,下次请求就可以命中缓存了。

优点:实现简单、维护方便

缺点:额外内存消耗、可能造成短期的数据不一致

布隆过滤:

请求会先通过布隆过滤器,如果数据不存在则会拒绝请求,如果存在就会先查询Redis再查询数据库

原理:将数据库的数据基于哈希算法将哈希值以二进制的形式放到布隆过滤器里面,这种过滤器是一种概率问题,当布隆过滤器拒绝就一定不存在,如果放行的话数据不一定存在,所以说还是有穿透的风险。

优点:内存占用少、没有多余key

缺点:实现复杂、存在误判的可能

解决穿透问题的业务逻辑

解决穿透问题除了上面的两种方法外还有其他的办法:

增强id的复杂度,避免被猜测id规律,我们可以通过前端判断id是否符合规范,从而过滤掉一些恶意的请求

做好数据的基础格式校验

加强用户权限校验(做访问次数的限流)

做好热点参数的限流

5.缓存雪崩

缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务器宕机,导致大量请求到达数据库,带来巨大压力。

解决方案:

大量的缓存key同时失效:

给不同的key的TTL添加随机值,通过random随机数将key失效时间控制到一段时间内,避免大量key同时失效。

Redis服务器宕机

利用Redis集群提高服务的可用性(Redis哨兵机制):通过集群主从的思想,主机宕机可以通过别的机器提高缓存服务,根据缓存的数据副本也不会导致数据丢失。

给缓存业务添加降级限流策略:对于一些查询服务,通过快速失效的方式,减少对数据库的压力,舍弃一些服务,从而保全数据库的健康。

给业务添加多级缓存:利用浏览器缓存、Tomcat的缓存,如果Redis宕机,可以由这些缓存缓解数据库压力,避免大量的查询落到数据库上。

6.缓存击穿

缓存击穿问题也叫热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会瞬间给数据库造成巨大的冲击。

缓存重建业务较复杂:如果我们需要缓存的对象业务比较复杂,需要通过多个表关联查询得到的数据,再去做缓存。这个过程时间相对比较久,这一时间段大量的请求落到数据库给数据库造成巨大冲击。

常见的解决方案:

互斥锁:

添加互斥锁,线程一在重新写入缓存的过程中,其他线程会获取互斥锁,获取失败会进入休眠,并且重新查询查看是否命中。也就是说在大量请求中只会由一个线程去查询数据库并构建缓存,其他线程只会进入阻塞状态。等待缓存重建成功。

优点:简单粗暴、保证一致性

缺点:会造成大量的线程等待、可能有死锁风险

逻辑过期:

存储缓存的时候不设置TTL,而是存储一个字段作为过期时间(当前时间+过期时间),所以是逻辑过期

为了避免获取锁后其他线程等待时间过长,他不是自己做查询和重建,而是开启一个新的线程来做,并且释放锁,自己会返回一个过期的数据,在此期间其他线程如果请求也会获取锁,获取失败会直接返回过期数据,避免线程的等待。

优点:线程无需等待、性能较好

缺点:不能保证一致性、有额外内存消耗、实现复杂

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决Keil V5.38 和 ST-Link V3 Debug不能运行问题

目录 概述 1 问题描述 1.1 情况一 1.2 情况二 1.3 情况三 2 解决方法 2.1 认识Keil Mico Lib 2.2 使能Keil Mico Lib 3 验证 3.1 进入C程序Main验证 3.2 断点验证 3.3 上电重启验证 4 结论 笔者使用的验证代码下载地址: stm32-freeRTOS-queue资源-CSD…

顺序表链表经典算法题

1.链表反转 typedef struct ListNode listnode; struct ListNode* reverseList(struct ListNode* head) {if(head NULL){return head;}listnode* p1 NULL;listnode* p2 head;listnode* p3 head->next;while(p2){p2->next p1;p1 p2;p2 p3;if(p3)p3 p3->next;}…

使用 Godot 游戏引擎为 Apple 的 visionOS 创建游戏和应用的平台

借助GodotVision ,您可以使用Godot 游戏引擎为 Apple VisionOS创建游戏和应用程序。 保卫牛城堡,一款使用 GodotVision 制作的 VisionOS 游戏 GodotVision 运行一个控制本机RealityKit 视图的无头 Godot实例。粗略地说:Godot 是后端,

二百三十三、Flume——Flume采集JSON文件到Kafka,再用Flume采集Kafka数据到HDFS中

一、目的 由于使用了新的Kafka协议,因为根据新的协议推送模拟数据到Kafka中,再Flume采集Kafka数据到HDFS中 二、技术选型 (一)Kettle工具 准备使用Kettle的JSON input控件和Kafka producer控件,但是搞了1天没搞定&…

如何用idm下载迅雷文件 idm怎么安装到浏览器 idm怎么设置中文

如果不是vip用户使用迅雷下载数据文件,其下载速度是很慢的,有的时候还会被限速,所以很多小伙们就开始使用idm下载迅雷文件,idm这款软件最大的优势就是下载速度快,还有就是具备网页捕获功能,能够下载网页上的…

【uniapp】 合成海报组件

之前公司的同事写过一个微信小程序用的 合成海报的组件 非常十分好用 最近的项目是uni的 把组件改造一下也可以用 记录一下 <template><view><canvas type"2d" class"_mycanvas" id"my-canvas" canvas-id"my-canvas" …

全开源小狐狸Ai系统 小狐狸ai付费创作系统 ChatGPT智能机器人2.7.6免授权版

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 测试环境&#xff1a;Linux系统CentOS7.6、宝塔、PHP7.4、MySQL5.6&#xff0c;根目录public&#xff0c;伪静态thinkPHP&#xff0c;开启ssl证书 具有文章改写、广告营销文案、编程…

Windows:web端UI自动化=python+selenium+pycharm框架

本篇写怎么写一个UI自动化代码。mac和Windows是一样的 都是这样写 不过&#xff0c;习惯用Windows了 如果python没有安装可以看我另一篇安装python的教程 先安装python先 下载完python 下载pip 1 安装pip $ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py # 下载…

宝塔面板使用docker+nginx+gunicorn部署Django项目实战教程

第一步&#xff1a;创建Django项目 使用pip install django安装创建django项目的依赖在电脑某个根目录下执行django-admin startproject app创建一个名为app的Django项目。目录结构如下: ├── app │ ├── init.py │ ├── asgi.py │ ├── settings.py │ ├── url…

机器学习:考试复习提纲

该页仅为复习资料&#xff0c;内含博客链接均通过搜索得到。 当然直接访问我的GitHub博客会更方便。 1. 线性回归 Linear Regression https://www.cnblogs.com/geo-will/p/10468253.html 要求1&#xff1a;可以按照自己的理解简述线性回归问题。 回归分析是一种预测性的建模…

buuctf re 37-40

[WUSTCTF2020]Cr0ssfun 打开 #include<iostream> using namespace std; int main() {char a1[32];a1[1] c;a1[25] ; a1[27] e;a1[4] 2;a1[17] r;a1[29] f;a1[17] r;a1[24] _;a1[2] t;a1[9] c;a1[32] };a1[19] v;a1[5] 0;a1[14] n;a1[15] d;a1[8] {;a1[18]…

【Leetcode每日一题】 动态规划 - 地下城游戏(难度⭐⭐⭐)(61)

1. 题目解析 题目链接&#xff1a;174. 地下城游戏 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 一、状态表定义 在解决地下城游戏问题时&#xff0c;我们首先需要对状态进行恰当的定义。一个直观的想法是&#x…

Oracle EBS Interface/API(54)- GL日记账审批

背景: 客户化创建薪酬凭证或者银企付款入账日记账以后,用户希望自动提交审批流程,无需到系统标准功能点击审批,减少用户操作。 快速参考 参考点内容功能导航N: GL->日记账->输入并发请求None基表GL.GL_JE_BATCHESAPI参考下面介绍错误信息表None接口FormNone接口Reque…

wiringpi库的应用 -- sg90 定时器 oled

sg 90舵机: 接线: VCC -- 红 GND -- 地 信号线 -- 黄 -- pwm 定时器: 先玩定时器: sg90 需要的pwm波需要定时器输出&#xff0c;so我们得先来玩一下定时器 分析&#xff1a;实现定时器&#xff0c;通过itimerval结构体以及函数setitimer产生的信号&#xff0c;系统…

Flume在大数据集群下的配置以及监控工具Ganglia的部署安装

前提&#xff1a;需要有三台虚拟机&#xff08;hadoop102,103,104&#xff09;配置好相关基础环境 安装 将安装包上传到/opt/software中 tar -zxf /opt/software/apache-flume-1.9.0-bin.tar.gz -C /opt/module/修改 apache-flume-1.9.0-bin 的名称为 flume mv /opt/module/…

Web安全知识

第二章 虚拟机运行架构&#xff1a; 1.寄居结构 2.原生架构 软件 注&#xff1a;Hyper-V是在Windows 2008操作系统上 附录 连接FTP服务器过程&#xff1a; 1.下载了软件&#xff1a; 2.连接到ftp://10.0.105.223/服务器&#xff08;访问老师课堂资源地址&#xff09; 关闭…

Node.JS后端开发笔记整理(简洁版)

前端 1. 开发环境和技术栈 开发工具&#xff1a;Visual Studio CodeNode.js版本&#xff1a;18.19.0&#xff08;建议保持在18&#xff09;包管理器&#xff1a;npm前端框架&#xff1a;Vue3.4脚本语言&#xff1a;TypeScript构建工具&#xff1a;Vite后端框架&#xff1a;Ex…

Django项目使用uwsgi+nginx部署上线

Django项目使用uwsginginx部署上线 前言settings 配置安装uwsgi 和配置uwsgi推荐配置文件启用wsgi不使用nginx的配置&#xff08;不推荐&#xff09;使用nginx的配置 安装 nginx和配置niginx 配置 运行参考资料 前言 代码已经开发完成&#xff0c;正式部署上线 settings 配置…

视频教程下载:用ChatGPT玩转海外抖音TikTok

CHATGPT for TikTok是一门前沿课程&#xff0c;旨在帮助您充分发挥TikTok广告活动的全部潜力。随着数字营销的爆炸性增长&#xff0c;企业需要使用先进的工具来保持竞争优势。在这门课程中&#xff0c;您将学习如何利用CHATGPT——一种先进的人工智能工具——来创建与目标受众产…

潜藏10年的恶意软件被发现;利用漏洞在K8S上挖矿;AWS、Google和Azure 出现信息泄露危机 | 安全周报0419

关键词&#xff1a;OfflRouter、恶意软件、VBA宏病毒、机密文件、可执行文件、iOS间谍软件、LightSpy、F_Warehouse、Azure CLI、AWS CLI、Google Cloud CLI 1. 近十年来&#xff0c;OfflRouter恶意软件在乌克兰一直未被发现 自2015年以来&#xff0c;部分乌克兰政府网络一直…
最新文章