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、解决方案

  1. 数据量不大的时候,工程启动的时候进行加载缓存动作

  2. 数据量大的时候,设置一个定时任务脚本,进行缓存的刷新

  3. 数据量太大的时候,优先保证热点数据进行提前加载到缓存。

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.永远不过期
  1. 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期

  2. 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在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);}}}

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

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

相关文章

Appium 自动化测试 —— Appium的环境搭建与设置流程!

1、Appium 环境搭建&#xff1a; 学习 appium 最大的难处之一在于环境的安装&#xff0c;安装流程比较繁琐&#xff0c;安装的工具和步骤也较多&#xff0c;以下是基于 Windows 系统下的 Android 手机端的安装流程。就像我们在用 Selenium 进行 web 自动化测试的时候一样&…

Python键鼠控制之PyAutoGUI方法

前言 PyAutoGUI 是一个 Python 库&#xff0c;用于在桌面应用程序中自动化鼠标和键盘操作。它提供了一组简单而强大的方法&#xff0c;使得开发者可以编写脚本来模拟用户的鼠标点击、键盘输入以及屏幕截图等操作。PyAutoGUI 可以用于自动化重复性任务、测试 GUI 应用程序、创建…

如何通过3D人脸扫描设备制作一个3D超写实虚拟人?

随着虚拟技术的快速发展&#xff0c;现如今的虚拟人逐渐逼真&#xff0c;比二次元虚拟偶像更接近真人形象的3D超写实虚拟人&#xff0c;拥有着更逼真的面部表情&#xff0c;更完美地融入于虚实画面。 随着3D人脸扫描设备不断发展&#xff0c;大大降低了高难度的3D超写实虚拟人…

Django 模型操作(六)

Django通过Model操作数据库, 不管你数据库的类型是MySql或者Sqlite, Django自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Django帮我们自动完成。只要会写Model就可以了。 django使用对象关系映射 (Object Relational Mapping, 简称ORM)框…

FPGA UltraScale GTY 全网最细讲解,aurora 8b/10b编解码,HDMI视频传输,提供vivado工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、详细设计方案设计框图视频源选择ADV7611解码芯片配置及采集动态彩条视频数据组包UltraScale GTY 全网最细解读UltraScale GTY 基本结构UltraScale GTY 参考时钟的选择和分配UltraScale GTY 发送和接收处理流程Ultr…

Datawhale聪明办法学Python(task2Getting Started)

一、课程基本结构 课程开源地址&#xff1a;课程简介 - 聪明办法学 Python 第二版 章节结构&#xff1a; Chapter 0 安装 InstallationChapter 1 启航 Getting StartedChapter 2 数据类型和操作 Data Types and OperatorsChapter 3 变量与函数 Variables and FunctionsChapte…

微积分-三角函数

三角函数 在处理微积分问题时&#xff0c;我们不可避免的会遇到三角函数。学会三角函数对于微积分是非常重要的。 基本知识 学习三角函数我们需要先学习一些基本知识。 首先要学习的是弧度的概念。弧度是一种角的度量单位&#xff0c;用于测量角的大小。它是根据角所对的弧长…

羊大师解答,羊奶的中医奇妙之处

羊奶素有“润肺之宝”之称&#xff0c;中医学认为它有着独特的作用和价值。羊奶不仅可以滋润肺部&#xff0c;还能保护肺脏免受外界侵害。在中医理论中&#xff0c;肺为人体之“金”&#xff0c;意味着肺具有极其重要的地位。正常肺气血充足&#xff0c;可以维持人体的正常生理…

Linux --绘制地图投影出现报错:无法成功下载地图背景数据

Linux --绘制地图投影出现报错&#xff1a;无法成功下载地图背景数据 主要原因是由于使用学院集群&#xff0c;该集群无法连接外网&#xff0c;在使用cartopy绘制地图投影时&#xff0c;导致无法成功加载地图背景数据解决方法也很简单&#xff0c;自己手动下载所需要的地形数据…

华清远见嵌入式学习——QT——作业4

作业要求&#xff1a; 代码运行效果图&#xff1a; 代码&#xff1a; 头文件&#xff1a; #ifndef ALARMCLOCK_H #define ALARMCLOCK_H#include <QWidget> #include <QTimerEvent> #include <QTimer> #include <QTime> #include <QTextToSpeech&g…

Github仓库远程操作——简单版

Github远程操作 github仓库简单的远程操作&#xff0c;更多复杂的功能请参考github官方文档 标题 Github远程操作添加公钥到githubGithub仓库远程操作 远程操作之前&#xff0c;先添加本地的公钥到github 添加公钥到github 创建本地ssh公私钥&#xff1a;使用powershell或者gi…

静态HTTP应用的未来趋势与展望

随着互联网的快速发展&#xff0c;静态HTTP应用作为一种简单、快速和安全的Web应用形式&#xff0c;已经得到了广泛的应用。然而&#xff0c;随着技术的不断进步和创新&#xff0c;静态HTTP应用也在不断发展和变化。下面&#xff0c;我们就来谈谈静态HTTP应用的未来趋势和展望。…

PHP+MySQL组合开发众筹系统源码:在线支付+消息通知+完整的代码包 附带完整的搭建教程

互联网的普及和发展&#xff0c;众筹作为一种新型的融资方式&#xff0c;逐渐受到越来越多人的关注和认可。众筹系统作为实现众筹业务的核心工具&#xff0c;其开发和应用对于推动众筹行业的发展具有重要意义。罗峰来给大家分享一款基于PHPMySQL组合开发的众筹系统源码&#xf…

软件测试--selenium安装使用

安装selenium不少人使用pip命令来安装selenium&#xff0c;辛辛苦苦安装完之后&#xff0c;还是不能使用。所以我们可以是直接使用编译器&#xff0c;pycharm直接安装selenium扩展包。 file中点击settings 在Settings中点击Project Interpreter,点击加号就可以安装各种需要的扩…

SD卡无法读取怎么办?详细解决方法分享!

“我的sd卡用了很久&#xff0c;但是不知道为什么无法读取了&#xff0c;尝试了很多种方法我都无法读取到里面的数据。我有很重要的文件保存在里面&#xff0c;想问问有什么方法可以帮助我快速解决这个问题吗&#xff1f;” SD卡是一种非常常用的存储设备&#xff0c;可以用于存…

2023 巅峰之作 | AIGC、AGI、GhatGPT、人工智能大语言模型的崛起与挑战

文章目录 01 《ChatGPT 驱动软件开发》内容简介 02 《ChatGPT原理与实战》内容简介 03 《神经网络与深度学习》04 《AIGC重塑教育》内容简介 05 《通用人工智能》目  录 2023年是人工智能大语言模型大爆发的一年&#xff0c;一些概念和英文缩写也在这一年里集中出现&#xff…

leetcode-24-两两交换链表中的节点(C语言实现)

题目&#xff1a; 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&…

详细了解云堡垒机的作用,提高企业数据信息安全

随着上云企业的不断增加&#xff0c;云上数据安全性成为企业面临的重要问题。为了保障企业的核心数据安全&#xff0c;越来越多的企业采购了云堡垒机来提升数据安全性。今天我们就来详细了解一下云堡垒机的作用&#xff0c;以及如何提高企业数据安全。 一、云堡垒机定义 云堡垒…

Python从入门到精通八:Python文件操作

文件的编码 思考&#xff1a;计算机只能识别&#xff1a;0和1&#xff0c;那么我们丰富的文本文件是如何被计算机识别&#xff0c;并存储在硬盘中呢&#xff1f; 答案&#xff1a;使用编码技术&#xff08;密码本&#xff09;将内容翻译成0和1存入。 编码技术即&#xff1a;…

Redux Toolkit(RTK)在React tsx中的使用

一个需求: header组建中有一个搜索框,然后这个搜索框在其他页面路由上都可以使用:例如这两个图共用顶部的搜索框; 我之前的做法就是组建传值, 在他们header 组建和 PageA ,B 的父级组件上定一个值,然后顶部变化传到父级组件,在从父级组件传到page组件,有点繁琐,现在说一下利用…