Redis:缓存穿透、缓存雪崩和缓存击穿(未完待续)

news2024/11/29 9:47:14

Redis的缓存穿透、缓存雪崩和缓存击穿

  • 一. 缓存穿透
    • 1.1 概念
    • 1.2 造成的问题
    • 1.3 解决方案
    • 1.4 案例:查询商铺信息(缓存穿透的实现)
  • 二. 缓存雪崩
    • 2.1 概念
    • 2.2 解决方案
  • 三. 缓存击穿(热点key)
    • 3.1 概念
    • 3.2 解决方案
    • 3.3 案例:查询商铺信息(互斥锁和逻辑过期的实现)
      • (1)互斥锁
        • 补充:SETNX(setIfAbsent)
      • (2)逻辑过期

一. 缓存穿透

1.1 概念

缓存模型;

定义:指客户请求的数据在缓存中和数据库中都不存在!这样缓存永远不会命中,请求都会发到数据库;
(穿透即穿透了缓存和数据库);
在这里插入图片描述

1.2 造成的问题

假设不断发送这样的请求,则会让数据库崩溃;

1.3 解决方案

(1)主动

  1. 增加请求参数的复杂度且有一定规范,对请求参数提前做校验
  2. 加强用户权限校验,如用拦截器校验登录状态;
  3. 热点参数的限流

(2)被动

  1. 缓存空对象
    为了不再让请求造成缓存穿透,则产生一个null空值(value=””)到redis中,当下次再请求时就可以从Redis返回而不用去查数据库;
    优点:简单
    缺点
    ①造成Redis中的内存消耗;----- 对这样的null值数据设置TTL有效时间;
    ②短期不一致:Redis中存了null值,但是数据库此时真的增加了这条数据,而缓存中数据和数据库不一样,当有用户来查询时会查到null数据;------ 缩短TTL时间 或者手动覆盖数据到Redis中
    在这里插入图片描述
  2. 布隆过滤
    【在请求访问Redis之前】添加一个布隆过滤器;
    布隆过滤器中存储的是byte字节数据,存储的是二进制位;
    数据库中的数据会经过Hash算法,将计算后的值到布隆过滤器,当请求发过来时,会判断请求的Hash值是否存在于过滤器中,若过滤器判断不存在则一定不存在;
    若过滤器判断存在,则只是可能存在,不是100%准确,所以依然有一定缓存穿透风险的;
    优点:内存占用少,只需要存Hash值,没有多余key
    缺点:实现相对复杂;可能误判(哈希冲突);
    在这里插入图片描述

1.4 案例:查询商铺信息(缓存穿透的实现)

业务逻辑
1.注入stringRedisTemplate的bean,从Redis查询商户缓存,如果命中则判断是不是空值,不是则返回商铺信息,是则返回不存在;
2.未命中则查询数据库,若不存在,报错;
3.若数据库中存在,则用stringRedisTemplate.opsForVlaue将商铺信息更新到Redis中,并更新TTL有效时间(兜底)!
4.如果数据库中也不存在(缓存穿透),则将空值写入Redis,即value=“”;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

效果
发送id不存在的查询请求,查询Redis和数据库,缓存穿透了,返回“不存在”,会在Redis缓存一个空值;
假设再发送同样的请求,则查询到Redis中的空字符串数据,还是返回“不存在”,但是不走数据库了!
在这里插入图片描述

总结:1. 缓存穿透则写入空值 2. Redis命中时需要判断是否为空字符串;

二. 缓存雪崩

2.1 概念

定义:同一时段内有①大量的缓存Key同时失效过期 或者 ②Redis服务宕机,导致大量请求发往数据库,带来巨大压力;
在这里插入图片描述

2.2 解决方案

(1)针对大量缓存同时失效:

  1. 给不同的key的TTL添加随机值
  2. 给缓存业务添加降级限流策略,牺牲部分服务,保护数据库;

(2)针对Redis宕机:

  1. 启用熔断机制暂停服务;
  2. 主从节点的方式建立Redis高可用集群哨兵机制 可以实现对服务的监控(类比Kafka),主从实现数据同步;
  3. 多个层面建立缓存,让Nginx也做缓存,Nginx未命中,再去Redis,再去JVM,最后才是数据库
    多级缓存在大型电商中如商品详情会使用,以应对亿级以上的并发;

三. 缓存击穿(热点key)

3.1 概念

定义
业务通常会有几个数据会被 ①频繁访问,比如秒杀活动,且 ②缓存重建业务比较复杂,这类被频地访问的数据被称为 热点数据

如果缓存中的某个热点数据过期了且缓存重建耗时较长,此时大量的请求线程都会去缓存重建,会对数据库带来巨大冲击;
在这里插入图片描述

3.2 解决方案

(1)互斥锁
所有请求都去尝试缓存重建,所以用互斥锁的方式只让一个请求线程去缓存重建
只有获取到锁的请求线程才能去进行缓存重建;而其他请求线程则休眠一会再查询,直到锁释放后,再访问到新的缓存;

优点:保持数据的一致性
缺点:线程需要等待,性能不好(牺牲可用性)
在这里插入图片描述

(2)逻辑过期

  1. 缓存穿透的原因就是因为热点数据过期,所以设置一个 逻辑过期 让热点数据在Redis中永不过期(不设置TTL);
    新增一个过期时间的字段放到Value中,让线程可以判断是否逻辑过期;(类似MyBatisPlus的逻辑删除),但实际上不是TTL,这样每次都能命中;
  2. 线程发现热点数据已经逻辑过期,就尝试获取互斥锁
    ①如果获取锁成功,则开启一个新的线程 去缓存重建原线程返回旧数据
    ②获取失败则返回旧数据;

优点:线程不需要等待,性能好(保证可用性)
缺点:牺牲一致性
在这里插入图片描述

注意
互斥锁方法和逻辑过期都用了互斥锁,前者当其他线程发现锁被占用后则会一直重试等待直到缓存重建完成;
后者当其他线程发现数据逻辑过期后才去尝试获取锁,锁被占用则获取旧的热点数据,而不会一直等待;

总结:互斥锁和逻辑过期都是在解决缓存重建时的并发问题; 互斥锁即让请求线程等待,保证一致性;逻辑过期是可以拿到旧数据即保证了可用性,但是牺牲了一致性

3.3 案例:查询商铺信息(互斥锁和逻辑过期的实现)

(1)互斥锁

流程
1.注入stringRedisTemplate的bean,从Redis查询商户缓存,如果命中返回商铺信息,
2.如果未命中则尝试获取锁,注意锁的key不是商铺id,
3.没有拿到锁则休眠一会,再重新尝试查询Redis(递归);
4.获取到锁则缓存重建,缓存重建需要去查询数据库,查完后更新Redis,释放锁;
5.返回结果;

先建立加锁和解锁两个方法:
为了防止锁永不释放,给锁加有效期(兜底)
在这里插入图片描述
业务逻辑:
在这里插入图片描述
在这里插入图片描述

测试
使用JMeter模拟多线程并发的场景;
设置1000个线程,时间共5s,QPS=200/s;
在这里插入图片描述

结果
Idea中显示只查询了一次数据库,成功;

补充:SETNX(setIfAbsent)

SETNX / setIfAbsent:(NX=not exist)即key不存在时才能set成功! 用来作 互斥锁 使用;


在这里插入图片描述
即相当于是互斥锁,只有第一个能成功!后面的都失败了!
释放锁:
在这里插入图片描述
为了防止锁永远不被释放,一般加有效期(兜底):假设10秒,一般业务执行在1秒内;

(2)逻辑过期

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

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

相关文章

网络基础概述

1.计算机网络背景 ​ 计算机刚刚发展的时候,是没有网络的,每一台计算机都是相互独立的。后来,人们有了多人协作的需求,人们就想办法把多台计算机用“线”连接起来,实现数据共享。后来,连接到一起的电脑越来…

地球板块运动vr交互模拟体验教学提高学生的学习兴趣

海陆变迁是地球演化史上非常重要的一个过程,它不仅影响着地球的气候、地貌、生物多样性等方面,还对人类文明的演化产生了深远的影响。为了帮助学生更加深入地了解海陆变迁的过程和机制,很多高校教育机构开始采用虚拟现实技术进行教学探究。 V…

Go语言进阶与依赖管理-学习笔记

1 语言进阶 1.1 Goroutine 线程:内核态,栈MB级别 协程:用户态,轻量级线程,栈KB级 1.2 CSP 提倡通信实现共享内存 1.3 Channel 创建方法 make(chan 元素类型,缓冲区大小) 无缓冲通道&#x…

【Storm】【二】安装

1 准备 1.1 准备linux服务器 本文搭建的是3节点的集群,需要3台linux服务器,我这里使用的是centos7版本的linux虚拟机,虚拟机网络配置如下: 主节点: master 192.168.92.90 从节点: slave1 192.168.92.…

Git 教程

目录1.简介:2.安装Git3.Git 如何工作状态区域4.使用Git5.Git配置5.1 创建仓库 - repository5.2 配置5.2.1 --global5.2.2 检查配置6. 查看工作区的文件状态6.1什么是工作区6.2 如果显示乱码的解决方式7.在工作区添加单个文件8. 添加工作区文件到暂存区9. 创建版本10…

Docker启动RabbitMQ,实现生产者与消费者

目录 一、Docker拉取镜像并启动RabbitMQ 二、Hello World (一)依赖导入 (二)消息生产者 (三)消息消费者 三、实现轮训分发消息 (一)抽取工具类 (二)启…

网络安全——数链路层据安全协议

作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.数据链路层安全协议简介 1.数据链路安全性 二.局域网数据链路层协议 1.…

git应用笔记(三)

在新增虚拟机linux的基础上,做git的下载与提交 1、初始化自己的用户名和邮箱。 git config --global user.name “输入你的用户名” git config --global user.email “输入你的邮箱” 2、将本地公钥及配置如图1复制粘贴到虚拟机当前用户.ssh\目录下 4929a0205f43…

面渣逆袭:分布式十二问,万字图文详解

大家好,我是老三,不管今年金三银四如何,面渣逆袭系列继续,这期我们来看看分布式。 分布式理论 1. 说说CAP原则? CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性…

硬件学习 软件Cadence day07 PCB 底板电路图布线

1.根据原理图的元器件, 选择在 PCB 芯片制作的元器件 (allegro中原理图和pcb中元件的交互) 1.首先完成下列操作 可以尝试先关闭再打开, 等下操作的时候就好 发现新增的发光物体!! 2.完成操作 ,…

Web3中文|香港拟允许比特币交易,瞄准“全球web3中心”

香港再次成为全球加密行业关注的焦点。在美国SEC对于加密货币交易所Kraken、BUSD发行商Paxos以及BA的重磅打击对比下,香港从去年开始持续拥抱Web3的姿态,让投资者开始押注香港。2023年2月20日,香港证监会宣布,就适用于虚拟资产交易…

Linux:基于libevent读写管道代码

基于libevent读写管道代码&#xff1a; 读端&#xff1a; #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <event2/event.h> #include…

gdb的简单练习

题目来自《ctf安全竞赛入门》1.用vim写代码vim gdb.c#include "stdio.h" #include "stdlib.h" void main() {int i 100;int j 101;if (i j){printf("bingooooooooo.");system("/bin/sh");}elseprintf("error............&quo…

Python 算法交易实验48 表字段设计

说明 虽然说的是表&#xff0c;实际上用的是Mongo集合 基于ADBS(APIFunc DataBase Service)可以构造一个供后续研究、生产长时间使用的数据基础&#xff0c;这个基础包括了&#xff1a; 1 队列服务。通过队列&#xff0c;数据可以通过API实现零担和批量两种模式的快速存储。2 …

ideal创建maven项目

前置工作本机安装mavenIdea 设置使用本机maven 工具Settings--->Maven开始创建maven项目创建maven项目&#xff0c;勾选通过模板创建&#xff0c;选择 maven-archetype-webapp 模板GroupId: 公司名倒序ArtifactId: 项目名设置本地maven仓库配置项目文件显示名&#xff0c;和…

外卖点餐小程序开发

前言 餐饮行业是一个传统的行业。根据当前发展现状,网络信息时代的全面普及,餐饮行业也在发生着变化,单就点餐这一方面,利用手机点单正在逐步进入人们的生活。传统的点餐方式,不仅会耗费大量的人力、时间,有时候还会出错。小程序系统伴随智能手机为我们提供了新的方向。 手机…

如何使用码匠连接 MySQL

目录 在码匠中集成 MySQL 在码匠中使用 MySQL 关于码匠 目前码匠已经实现了与 MySQL 数据源的连接&#xff0c;支持书写 SQL 语句&#xff0c;也支持通过图形化界面对数据进行增、删、改、查&#xff0c; 同时还支持将数据绑定至各种组件&#xff0c;并通过简单的代码实现数据…

Collecting package metadata (current_repodata.json): failed

一、问题描述 安装anaconda之后&#xff0c;想创建环境&#xff0c;用了下面这段代码&#xff1a; conda create -n pytorch python3.7 conda创建环境报错了&#xff0c;报了如下这一堆&#xff1a; Collecting package metadata (current_repodata.json): failedUnavailab…

echart中x轴数据过多时展示不全

项目中遇到需要展示一些柱状图&#xff0c;之前做相关功能时&#xff0c;横坐标x轴一直用的是时间&#xff0c;所以没有注意到这个问题。 如下图所示&#xff1a; 当x轴显示的是”人名“这种类型的值的时候&#xff0c;这种显示情况就有问题了&#xff0c;这样就不会知道&…

python学习笔记之例题篇NO.3

获得用户输入的一个整数N&#xff0c;输出N中所出现不同数字的和。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬ s list(set(list(input())))# ① r…