Redis缓存异常问题,常用解决方案总结
前言
Redis缓存异常问题分别是:1.缓存雪崩。2.缓存预热。3.缓存穿透。4.缓存降级。5.缓存击穿,以
及对应Redis缓存异常问题解决方案。
1.缓存雪崩
1.1、什么是缓存雪崩
如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩由于原有缓存失效,新缓存未到期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。
举例来说, 我们在准备一项抢购的促销运营活动,活动期间将带来大量的商品信息、库存等相关信息的查询。
为了避免商品数据库的压力,将商品数据放入缓存中存储。不巧的是,抢购活动期间,大量的热门商品缓存同时失
效过期了,导致很大的查询流量落到了数据库之上,对于数据库来说造成很大的压力。
1.2、解决方案
1、加锁排队
mutex互斥锁解决,Redis的SETNX去set一个mutex key,当操作返回成功时,再进行加载数据库的操作并回设缓存,否则,就重试整个get缓存的方法。
2、数据预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据。可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key。
3、双层缓存策略
C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期。
4、定时更新缓存策略
实效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存。
5、设置不同的过期时间。
让缓存失效的时间点尽量均匀。
2.缓存预热
2.1、什么是缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据。
如图所示:

如果不进行预热, 那么 Redis 初识状态数据为空,系统上线初期,对于高并发的流量,都会访问到数据库中, 对数据库造成流量的压力。
2.2、解决方案
-
数据量不大的时候,工程启动的时候进行加载缓存动作;
-
数据量大的时候,设置一个定时任务脚本,进行缓存的刷新;
-
数据量太大的时候,优先保证热点数据进行提前加载到缓存。
3.缓存穿透
3.1、什么是缓存穿透
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到对应key的value,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库。
3.2、解决方案
1、缓存空对象
简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
2、布隆过滤器
优势:占用内存空间很小,位存储;性能特别高,使用key的hash判断key存不存在。
将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
4.缓存降级
降级的情况,就是缓存失效或者缓存服务挂掉的情况下,我们也不去访问数据库。
我们直接访问内存部分数据缓存或者直接返回默认数据。
举例来说:
对于应用的首页,一般是访问量非常大的地方,首页里面往往包含了部分推荐商品的展示信息。这些推荐商品都会放到缓存中进行存储,同时我们为了避免缓存的异常情况,对热点商品数据也存储到了内存中。同时内存中还保留了一些默认的商品信息。

降级一般是有损的操作,所以尽量减少降级对于业务的影响程度。
5.缓存击穿
5.1、什么是缓存击穿
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没
读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
5.2、会带来什么问题
会造成某一时刻数据库请求量过大,压力剧增。
5.3、解决方案
5.3.1.使用互斥锁(mutex key)
这种解决方案思路比较简单,就是只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据就可以了。
如果是单机,可以用synchronized或者lock来处理;
如果是分布式环境可以用分布式锁就可以了(分布式锁,可以用memcache的add, redis的setnx, zookeeper的添加节点操作)。

5.3.2.永远不过期
-
从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
-
从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期。

5.3.3.缓存屏障
该方法类似于方法一:
使用countDownLatch和atomicInteger.compareAndSet()方法,实现轻量级锁。
public class MyCache{private ConcurrentHashMap<String, String> map;private CountDownLatch countDownLatch;private AtomicInteger atomicInteger;public MyCache(ConcurrentHashMap<String, String> map, CountDownLatch countDownLatch,AtomicInteger atomicInteger) {this.map = map;this.countDownLatch = countDownLatch;this.atomicInteger = atomicInteger;}public String get(String key){String value = map.get(key);if (value != null){System.out.println(Thread.currentThread().getName()+"\t 线程获取value值 value="+value);return value;}// 如果没获取到值// 首先尝试获取token,然后去查询db,初始化化缓存;// 如果没有获取到token,超时等待if (atomicInteger.compareAndSet(0,1)){System.out.println(Thread.currentThread().getName()+"\t 线程获取token");return null;}// 其他线程超时等待try {System.out.println(Thread.currentThread().getName()+"\t 线程没有获取token,等待中。。。");countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}// 初始化缓存成功,等待线程被唤醒// 等待线程等待超时,自动唤醒System.out.println(Thread.currentThread().getName()+"\t 线程被唤醒,获取value ="+map.get("key"));return map.get(key);}public void put(String key, String value){try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}map.put(key, value);// 更新状态atomicInteger.compareAndSet(1, 2);// 通知其他线程countDownLatch.countDown();System.out.println();System.out.println(Thread.currentThread().getName()+"\t 线程初始化缓存成功!value ="+map.get("key"));}}public class MyThread implements Runnable{private MyCache myCache;public MyThread(MyCache myCache) {this.myCache = myCache;}@Overridepublic void run() {String value = myCache.get("key");if (value == null){myCache.put("key","value");}}}public class CountDownLatchDemo {public static void main(String[] args) {MyCache myCache = new MyCache(new ConcurrentHashMap<>(), new CountDownLatch(1), new AtomicInteger(0));MyThread myThread = new MyThread(myCache);ExecutorService executorService = Executors.newFixedThreadPool(5);for (int i = 0; i < 5; i++) {executorService.execute(myThread);}}}
相关文章:
Redis缓存异常问题,常用解决方案总结
前言 Redis缓存异常问题分别是:1.缓存雪崩。2.缓存预热。3.缓存穿透。4.缓存降级。5.缓存击穿,以 及对应Redis缓存异常问题解决方案。 1.缓存雪崩 1.1、什么是缓存雪崩 如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有…...
java开发的智能聊天机器人_超级AI_支持自动绘画功能
支持Web、Android、IOS、H5等多终端应用。它使用OpenAI的ChatGPT模型实现智能聊天机器人,并支持绘图自动生成Vincent图。未来还将接入国内大型AI模型,如文心一言、统一千问、MOSS等模型,并不断更新以满足用户需求。 AI大脑软件中的AI绘画功能…...
亚马逊云科技:向量数据存储在生成式人工智能应用程序中的作用
生成式人工智能深受大众喜爱,并且由于具备回答问题、写故事、创作艺术品甚至生成代码的功能,推动了行业的转变,那么如何才能在自己的企业中充分地利用生成式人工智能等应运而生问题。许多客户已经积累了大量特定领域的数据(财务记…...
小程序面试总结
简单描述下微信小程序的相关文件类型 微信小程序主要涉及以下几种文件类型: JSON 文件(.json): 用于描述小程序的配置信息,比如全局配置、页面路径、窗口样式等。WXML 文件(.wxml):…...
mac 安装anaconda和lightgbm
1.mac安装anaconda 要去[官网](Free Download | Anaconda)下载安装包 不要去清华大学的anaconda的安装包列表去下载安装包,清华的版本太老了, 老到连conda install 安装lightgbm都不只支持 2.安装好anaconda 后, 能用conda install xxx 的尽量不用pip 用pip install light…...
Flink 有状态流式处理
传统批次处理方法 【1】持续收取数据(kafka等),以window时间作为划分,划分一个一个的批次档案(按照时间或者大小等); 【2】周期性执行批次运算(Spark/Stom等);…...
LeetCode //C - 1071. Greatest Common Divisor of Strings
1071. Greatest Common Divisor of Strings For two strings s and t, we say “t divides s” if and only if s t … t (i.e., t is concatenated with itself one or more times). Given two strings str1 and str2, return the largest string x such that x divides …...
智能优化算法应用:基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于群居蜘蛛算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.群居蜘蛛算法4.实验参数设定5.算法结果6.…...
AtCoder Beginner Contest 332
E - Lucky bag(简单状态压缩dp) 题目链接 题意:给你n个物品,m个福袋,让你将这n个物品用m个福袋打包(福袋可以为空),让分完之后的总方差最小,输出最小方差。 思路:其实由题目的数据…...
华为OD试题二(文件目录大小、相对开音节、找最小数)
1. 文件目录大小 题目描述: 一个文件目录的数据格式为:目录id,本目录中文件大小,(子目录id 列表)。其中目录id全局唯一,取值范围[1,200],本目录中文件大小范 围[1,1000],子目录id列表个数[0,10…...
【Spark精讲】Spark作业执行原理
基本流程 用户编写的Spark应用程序最开始都要初始化SparkContext。 用户编写的应用程序中,每执行一个action操作,就会触发一个job的执行,一个应用程序中可能会生成多个job执行。一个job如果存在宽依赖,会将shuffle前后划分成两个…...
Docker容器:Centos7搭建Docker镜像私服harbor
目录 1、安装docker 1.1、前置条件 1.2、查看当前操作系统的内核版本 1.3、卸载旧版本(可选) 1.4、安装需要的软件包 1.5、设置yum安装源 1.6、查看docker可用版本 1.7、安装docker 1.8、开启docker服务 1.9、安装阿里云镜像加速器 1.10、设置docker开机自启 2、安…...
ClickHouse安装和部署
ClickHouse安装过程: ClickHouse支持运行在主流64位CPU架构(X86、AArch和PowerPC)的Linux操作 系统之上,可以通过源码编译、预编译压缩包、Docker镜像和RPM等多种方法进行安装。由于篇幅有限,本节着重讲解离线RPM的安…...
Spring Cloud Gateway中对admin端点进行认证
前言 我们被扫了一个漏洞,SpringBoot Actuator 未授权访问,漏洞描述是这样的: Actuator 是 springboot 提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator 开发者可以很方便地对应用系统某些监控指标进行查看、统计…...
2. 如何通过公网IP端口映射访问到设备的vmware虚拟机的ubuntu服务器
文章目录 1. 主机设备是Windows 11系统2. 安装vmware虚拟机3. 创建ubuntu虚拟机(据说CentOS 7 明年就不维护了,就不用这个版本的linux了)4. 安装nginx服务:默认端口805. 安装ssh服务:默认端口226. 设置主机 -> ubuntu的端口映射7. 设置路由…...
配置android sudio出现的错误
导入demo工程,配置过程参考: AndroidStudio导入项目的正确方式,修改gradle配置 错误:Namespace not specified. Specify a namespace in the module’s build file. 并定位在下图位置: 原因:Android 大括号…...
【初阶C++】前言
C前言 1. 什么是C2. C发展史3. C的重要性4. 如何学习C 1. 什么是C C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, …...
MAC IDEA Maven Springboot
在mac中,使用idea进行maven项目构建 环境配置如何运行maven项目1.直接在IDEA中运行2.使用jar打包后执行 如何搭建spring boot1.添加依赖2.创建入口类3.创建控制器4. 运行5.其他 环境配置 官网安装IDEA使用IDEA的创建新项目选择创建MAEVEN项目测试IDEA的MAVEN路径是…...
Angular13无法在浏览器debug
前言 本文将介绍如何解决在Angular 13中无法在浏览器中进行调试的问题,并提供了一种解决方法。 发生场景 根据项目需求,升级至Angular 13后,发现无法在浏览器中进行调试。 问题原因 无法进行调试的原因是,当使用Angular 13的…...
H.264与H.265(HEVC):视频编码的演进
目录 H.264的发展历程 1. 标准发布 2. 广泛应用 3. 专业化应用 H.265的出现...
CUDA12.4环境适配:OpenClaw调用Qwen3-14B镜像的驱动配置详解
CUDA12.4环境适配:OpenClaw调用Qwen3-14B镜像的驱动配置详解 1. 为什么需要关注CUDA环境适配 上周我在本地部署Qwen3-14B镜像时,遇到了一个典型问题:模型加载到一半突然崩溃,控制台只留下一行模糊的CUDA错误提示。经过两天排查才…...
OpenClaw技能开发入门:为Qwen3.5-9B-AWQ-4bit定制图片OCR模块
OpenClaw技能开发入门:为Qwen3.5-9B-AWQ-4bit定制图片OCR模块 1. 为什么需要定制OCR技能 去年我在整理几千张产品截图时,发现现有的OCR工具存在三个痛点:无法自动矫正倾斜拍摄的图片、识别结果缺乏结构化处理、无法与工作流联动。这正是Ope…...
c++编程:说反话(1009-PAT乙级)
1009:说反话cin >> 读取字符串时不能读取空格string s; cin >> s; // 输入 "hello world" cout << s; // 输出 "hello"(空格后面的被丢弃)如何读取带空格的整行?getline()str…...
杰理之开mic关mic复位问题处理【篇】
开PC模式...
Kafka消费者组性能调优实战:从瓶颈识别到极致优化
前言“Kafka性能调优,20%是调整配置,80%是理解你的工作负载。”这是无数生产环境事故总结出来的血泪教训。在生产实践中,很多团队遇到消费性能问题时,第一反应是“加机器、加分区、调参数”,结果往往事倍功半ÿ…...
8086 汇编报错全总结与归纳
一、可能遇到的所有错误汇总错误代码错误含义触发行(你的代码)核心根源A2048Must be index or base registermov [ax],1H、add [dx],[ax]8086 硬件不支持用非BX通用寄存器做内存间接寻址A2035Operand must have sizemov [bx],1H汇编器无法判断操作数是 8…...
《C 头文件》
《C 头文件》 引言 C 头文件是 C 语言编程中不可或缺的一部分。它们包含了 C 语言标准库中的各种函数、宏定义和类型定义,为程序员提供了丰富的编程工具。本文将详细介绍 C 头文件的作用、分类、常用头文件及其在编程中的应用。 一、C 头文件的作用 C 头文件的主要作用有以…...
基于stm32单片机的智能导盲系统的设计与实现
一、摘要 为提高视障人群出行的安全性与便捷性,设计并实现一套基于STM32F103C8T6单片机的智能导盲系统。系统集成多种传感器与功能模块,能够实现环境感知、位置信息反馈、跌倒检测与紧急求助等功能。通过SR04超声波传感器实时监测前方障碍物,…...
FastBle单元测试终极指南:Mockito在Android蓝牙BLE开发中的7个实战技巧
FastBle单元测试终极指南:Mockito在Android蓝牙BLE开发中的7个实战技巧 【免费下载链接】FastBle Android Bluetooth Low Energy (BLE) Fast Development Framework. It uses simple ways to filter, scan, connect, read ,write, notify, readRssi, setMTU, and mu…...
【Hot 100 刷题计划】 LeetCode 438. 找到字符串中所有字母异位词 | C++ 滑动窗口题解
LeetCode 438. 找到字符串中所有字母异位词 | C 固定滑动窗口极致优化题解 📌 题目描述 题目级别:中等 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词ÿ…...
