【Redis进阶】缓存应用

news2024/9/22 15:31:50

目录

缓存击穿

概念

缓存击穿的原因

缓存击穿的影响

缓存击穿的应对措施

设置分布式锁

提前更新缓存

请求分级和降级

缓存穿透

概念

缓存穿透的原因

缓存穿透的应对措施

缓存空值

布隆过滤器

 限流和黑名单

缓存雪崩

缓存雪崩概念

缓存雪崩的原因

应对措施

缓存过期时间随机化:

多级缓存架构

限流

预热缓存


缓存击穿

概念

缓存击穿是指缓存中不存在但数据库中存在的数据请求,由于缓存没有命中,导致请求直接落到数据库上,造成数据库压力骤增。缓存击穿常常发生在某些热点数据上,比如某个高访问频率的热点键突然失效时,大量请求直接穿透缓存访问数据库。

缓存击穿的原因

热点数据缓存失效:高访问频率的热点数据在缓存中失效,导致大量请求直接访问数据库。

缓存设置不当:如缓存策略不合理,过期时间设置过短等

突发流量:突发性的大量请求几种访问某个热点数据,导致缓存来不及重建,直接击穿到数据库。

缓存击穿的影响

数据库压力骤增:大量请求直接访问数据库,可能导致数据库负载过高甚至崩溃。

响应延迟增加:缓存击穿会导致请求需要经过数据库查询,响应时间变长,影响用户体验。

系统稳定性降低:数据库过载可能引发系统不稳定,甚至导致服务不可用。

缓存击穿的应对措施

设置分布式锁

在缓存失效时,通过加锁机制,确保只有一个线程去加载数据并更新缓存,其他线程等待锁释放后再读取缓存。

提前更新缓存

在缓存失效前主动更新缓存。可以使用定时任务或异步任务,在缓存即将过期时提前刷新缓存。

请求分级和降级

  • 针对缓存击穿的情况,可以对请求进行分级处理,优先保证核心请求。
  • 对非核心请求进行降级处理,如返回默认值或错误提示。

缓存穿透

概念

缓存穿透是指请求的数据既不在缓存中,也不存在于数据库中,导致每次请求都直接达到数据库。由于这些请求无法通过缓存过滤掉,所有的请求都到达数据库。可能会对数据库造成巨大压力。

缓存穿透的原因

恶意攻击:攻击者故意构造大量不存在的key进行请求,绕过缓存,直接打到数据库,造成数据库压力骤增。

业务设计缺陷:正常业务逻辑中,存在大量的不存在的数据请求,未合理处理,导致频繁穿透缓存。

用户错误输入:用户输入错误或者不规范的数据,导致请求的数据在缓存和数据库中都不存在。

缓存穿透的应对措施

缓存空值

  • 对于查询结果为空的数据,也将其缓存起来,避免下一次请求再次穿透过数据库。
String key = "nonExistingKey";
String value = redis.get(key);

if (value == null) {
    value = db.get(key);
    if (value == null) {
        // 将空值写入缓存,并设置合理的过期时间
        redis.set(key, "", 60); // 60秒过期
    } else {
        redis.set(key, value, 300); // 300秒过期
    }
}

布隆过滤器

  • 使用布隆过滤器在缓存前进行一次快速判断,如果布隆过滤器判断该 key 不存在,则直接返回,不再查询缓存和数据库。
// 初始化布隆过滤器
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), expectedInsertions);

// 添加存在的key到布隆过滤器
bloomFilter.put("existingKey1");
bloomFilter.put("existingKey2");

String key = "nonExistingKey";
if (!bloomFilter.mightContain(key)) {
    return null; // 直接返回,不查询缓存和数据库
}

// 正常的缓存和数据库查询流程
String value = redis.get(key);
if (value == null) {
    value = db.get(key);
    redis.set(key, value);
}

 限流和黑名单

  • 对于明显的恶意请求,可以采取限流和黑名单策略,限制其访问频率或直接拒绝其请求。
String clientIp = getClientIp();
if (isBlacklisted(clientIp)) {
    return null; // 直接返回,不查询缓存和数据库
}

// 正常的缓存和数据库查询流程
String key = "someKey";
String value = redis.get(key);
if (value == null) {
    value = db.get(key);
    redis.set(key, value);
}

缓存雪崩

缓存雪崩概念

缓存雪崩是指由于大量缓存数据在同一时间过期或失效,导致后续的所有请求都直接访问数据库,瞬间增加数据库的负载。与缓存击穿不同,缓存雪崩通常影响的是大批量的缓存数据,而不是单个热点数据。

缓存雪崩的原因

  • 缓存过期时间设置不合理:大批量缓存键设定了相同或相近的过期时间,导致它们在同一时间点失效。
  • 突发流量:在流量高峰期,如果缓存失效,短时间内会有大量请求同时涌入数据库。
  • 缓存服务宕机:缓存服务(如 Redis 实例)出现宕机或重启,导致所有缓存失效,所有请求直接击中数据库。

应对措施

缓存过期时间随机化:

  • 在设置缓存过期时间时,添加一定的随机时间,使得不同的缓存键有不同的过期时间,避免大量缓存键在同一时间失效。
// 伪代码示例
int baseExpireTime = 600; // 基础过期时间600秒
int randomTime = new Random().nextInt(300); // 随机附加300秒
int expireTime = baseExpireTime + randomTime;
redis.set(key, value, expireTime);

多级缓存架构

  • 通过引入本地缓存(如 Guava Cache)和分布式缓存(如 Redis)相结合的多级缓存架构,减少直接访问数据库的请求数量。
// 伪代码示例
String key = "someKey";
String value = localCache.get(key);

if (value == null) {
    value = redis.get(key);
    if (value == null) {
        value = db.get(key);
        redis.set(key, value);
    }
    localCache.put(key, value);
}

限流

  • 通过限流机制控制高并发请求的流量,防止因大量请求同时访问数据库而导致数据库崩溃。
// 伪代码示例
if (!rateLimiter.tryAcquire()) {
    return "Service is busy, please try again later.";
}

String key = "someKey";
String value = redis.get(key);

if (value == null) {
    value = db.get(key);
    redis.set(key, value);
}

return value;

预热缓存

  • 在高峰期来临之前,预先将热点数据加载到缓存中,避免在流量高峰期缓存失效导致的雪崩。
// 伪代码示例
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void preheatCache() {
    String key = "hotKey";
    String value = db.get(key);
    redis.set(key, value);
}

希望本文能帮助大家更好地理解和应对 Redis 缓存击穿,缓存穿透,缓存雪崩问题。

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

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

相关文章

gogs的安装和使用(docker)

1.docker安装gogs 1.1 拉取gogs镜像 docker pull gogs/gogs #也可改为自己需要的版本号 1.2 创建存储目录 mkdir /root/gogs 1.3 运行镜像 docker run --namegogs -d -p 10022:22 -p 13000:3000 -v /root/gogs:/data gogs/gogs 1.3.1 指令解析 --namegogs: 指定名称…

力扣刷题-轮转数组

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 首先&#xff0c;我们现在这里提供的是一种特别简单的思路&#xff0c;我们先来看一下这段代码&#xff1a; void rotate(int* nums, int numsSize, int k) {k%numsSize;int n…

深入了解核函数:连接机器学习与统计学的桥梁

引言 在机器学习中&#xff0c;支持向量机&#xff08;SVM&#xff09;是一种强大的监督学习模型&#xff0c;特别适合处理分类问题。然而&#xff0c;SVM最初被设计用于线性可分的数据集&#xff0c;现实中的数据往往不是线性可分的。为了解决这一问题&#xff0c;我们引入了…

第十一届MathorCup高校数学建模挑战赛-C题:基于有限差分法的散热机理建模与海底数据中心优化设计

目录 摘 要 1 问题重述 1.1 问题背景 1.2 问题重述 2 问题分析 3 模型假设 4 符号说明 5 我们的工作 6 模型的建立与求解 6.1 建模前的准备 6.2 问题一的建模与求解 6.3 问题二的建模与求解 6.4 问题三的建模与求解 6.5 问题四的建模与解决 7 结果检验及误差分析 8 模型评价 9 …

[Modbus] Modbus协议开发-基本概念(一)

历史 ModBus官网是Modicon&#xff08;Modicon早年已被施耐德收购&#xff09;公司为其PLC通讯而开发的一种通讯协议。 概述 通过Modbus协议&#xff0c;控制器之间、或控制器经由网络&#xff08;如以太网&#xff09;可以和其它设备之间进行通信。 优点 免费、好用、成熟…

springboot项目搭建集成 redis/跨域/远程请求

目录 一&#xff0c;创建maven项目 1&#xff0c;左上角file > new > maven project 2&#xff0c;next 到 创建 Group id 和 Artifact id​编辑​编辑 二&#xff0c;配置springboot 1&#xff0c;配置pom文件&#xff0c; 2&#xff0c;创建启动类 3&#xff…

五段式S型算法笔记

设定已知&#xff1a;v0 vmax j&#xff1b; 减加速段&#xff1a;tm到tmax 加加速段&#xff1a;0到tm tm&#xff1a;中点时间 vm&#xff1a;中点速度 vmax&#xff1a;最大速度&#xff1b; j加速度的斜率 -j相反加速度的斜率 这个图首先说明&#xff…

大数据面试SQL(六):共同使用ip用户检测问题

文章目录 共同使用ip用户检测问题 一、题目 二、分析 三、SQL实战 四、样例数据参考 共同使用ip用户检测问题 一、题目 现有用户登录日志表&#xff0c;记录了每个用户登录的IP地址&#xff0c;请查询共同使用过3个及以上IP的用户对。 样例数据&#xff1a; 结果数据&…

NSSCTF练习记录:[SWPUCTF 2021 新生赛]jicao

题目&#xff1a; 这段PHP代码的意思是&#xff1a; 对index.php文件进行语法高亮显示&#xff0c;插入flag.php文件&#xff0c;变量id的值为POST传递的值&#xff0c;变量json的值为GET传递的json类型的值。当id值为wllmNB且json中含有键为“x”&#xff0c;值为“wllm”的时…

【Android】安卓四大组件之Service用法

文章目录 使用Handler更新UIService基本特点启动方式非绑定式服务使用步骤 绑定式服务步骤 生命周期非绑定式启动阶段结束阶段 绑定式启动阶段结束阶段 前台Service使用步骤结束结束Service本身降级为普通Service降级为普通Service 使用Handler更新UI 主线程创建Handler对象&a…

文件描述符中设置FD_CLOEXEC的用处

linux中&#xff0c;父进程fork出子进程&#xff0c;子进程本身会继承父进程的所有文件描述符。若子进程再调用exec系列函数转化为新的进程实体&#xff0c;其实父进程的描述符对其没有意义。此时文件上只需要设置FD_CLOEXEC即可。 下面是例子说明&#xff1a; #include <…

vue3、uniapp-vue3模块自动导入

没有使用插件 使用插件,模块自动导入 安装: npm i -D unplugin-auto-importvite.config.js (uniapp没有此文件,在项目根目录下创建) import { defineConfig } from "vite"; import uni from "dcloudio/vite-plugin-uni"; import AutoImport from &qu…

SpringBoot 自定义 Starter 实现

一、定义&#xff0c;什么是Starter SpringBoot Starter 是”一站式服务&#xff08;one-stop service&#xff09;“的依赖 Jar 包&#xff1a; 包含 Spring 以及相关技术&#xff08;比如Redis&#xff09;的所有依赖提供了自动配置的功能&#xff0c;开箱即用提供了良好的…

7. Kubernetes核心资源之Service服务实战

**service分类 : ** **ClusterIP : ** 默认类型&#xff0c;自动分配一个【仅集群内部】可以访问的虚拟IP **NodePort : ** 对外访问应用使用&#xff0c;在ClusterIP基础上为Service在每台机器上绑定一个端口&#xff0c;就可以通过: ipNodePort来访问该服务 **LoadBalanc…

[24年新算法]NRBO-XGBoost回归+交叉验证基于牛顿拉夫逊优化算法-XGBoost多变量回归预测

[24年新算法]NRBO-XGBoost回归交叉验证基于牛顿拉夫逊优化算法-XGBoost多变量回归预测 多输入单输出 程序已调试好&#xff0c;无需更改代码替换数据直接使用&#xff01;&#xff01;&#xff01;数据格式为excel格式&#xff01;如下。 中文注释清晰&#xff0c;图很丰富 …

2. C++的指针作用

目录 1.问题描述及分析 2.结论 不同类型所产生的指针在C语言中有什么作用&#xff1f;带着这个疑问&#xff0c;对C的指针进行简介。 1.问题描述及分析 在如下的一段代码中&#xff0c;分别有4个指针&#xff0c;这四个指针有什么不一样的地方么&#xff1f; class ZooAni…

Unity物理模块 之 ​2D刚体

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​ 1.刚体是什么 在 Unity 中&#xff0c;刚体&#xff08;Rigidbody&#xff09; 是物理引擎中最基本的组件之一&#x…

Python 函数(2)

2、函数 2.1、函数传递列表 将列表传递给函数后&#xff0c;函数就能直接访问其内容。 下列为一个实例&#xff1a;将一个名字列表传递给一个名为greet_users()的函数&#xff0c;这个函数将会向列表中的每一个元素执行相应的信息。 def greet_users(name):for name in name…

1.2 C 语言开发环境 CLion 的安装(含 Windows 和 Mac )

目录 1 C 语言的由来 2 安装 MinGW 编译器 3 Windows 中安装 CLion 开发环境 3.1 安装 CLion 开发环境 3.2 运行试用 30 天 3.3 新建项目​ 3.​4 激活 3.5 汉化 4 Mac 中安装 Clion 开发环境 4.1 安装 CLion 开发环境 4.2 运行试用 30 天 4.3 新建项目 ​4.4 激活…

RuoYi-Vue源码阅读(三):用户相关模块

文章目录 1 用户角色权限信息 getInfo1.1 后端代码实现步骤1.1.1 获取用户角色权限信息1.1.2 获取用户的角色集合 1.2 前端代码实现步骤 2 获取用户路由信息 getRouters2.1 后端代码实现步骤2.1.1 获取菜单目录2.1.2 构建前端路由所需要的菜单 2.2 前端代码实现步骤 3 参考链接…