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.hqwc.cn/news/269450.html

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

相关文章

Android12-RK3588_s-开机动画

目录 一、实现自定义开机动画 步骤一&#xff1a;准备 bootanimation.zip 步骤二&#xff1a;将 bootanimation.zip 放到 /system/media/bootanimation.zip下 步骤三&#xff1a;重启即可 二、注意事项 2.1 bootanimation.zip 压缩 2.2 bootanimation.zip 存放 2.3 boo…

AI全栈大模型工程师(二十七)如何部署自己 fine-tune 的模型

服务器价格计算器 火山引擎提供的这个价格计算器很方便&#xff0c;做个大概的云服务器 GPU 选型价格参考。其它服务厂商价格相差不是很多。 https://www.volcengine.com/pricing?productECS&tab2 高稳定和高可用地部署模型 序号模块名称描述1负载均衡将流入的请求分发到多…

AMEYA360--罗姆与Quanmatic公司利用量子技术优化制造工序并完成验证

全球知名半导体制造商罗姆(总部位于日本京都市)于2023年1月起与 Quanmatic Inc.(总部位于日本东京都新宿区&#xff0c;以下简称“Quanmatic”)展开合作&#xff0c;在半导体制造工序之一的EDS工序中测试并引入量子技术&#xff0c;以优化制造工序中的组合。目前&#xff0c;双…

技术资讯:VSCode大更新,这两个功能终于有了

大家好&#xff0c;我是大澈&#xff01; 本文约1200字&#xff0c;整篇阅读大约需要2分钟。 感谢关注微信公众号&#xff1a;“程序员大澈”&#xff0c;然后免费加入问答群&#xff0c;从此让解决问题的你不再孤单&#xff01; 1. 资讯速览 就在前阵子&#xff0c;前端人都…

大数据毕业设计之前端03:logo、menu的折叠展开实现

关键字&#xff1a;BuildAdmin、pinia、logo、aside、menu、菜单折叠、Vue、ElementUI 前言 上一篇文章中&#xff0c;借助aside的实现讲了一些开发的小技巧&#xff0c;以及css的解读。本篇文章主要写一下如何填充aside的内容。 aside主要是由两个部分组成的&#xff1a;log…

Apollo配置发布原理解析

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

金融银行软件测试超大型攻略,最受欢迎的金融银行大揭秘附面试题

零、为什么做金融类软件测试 举个栗子&#xff0c;银行里的软件测试工程师。横向跟互联网公司里的测试来说&#xff0c;薪资相对稳定&#xff0c;加班少甚至基本没有&#xff0c;业务稳定。实在是测试类岗位中的香饽饽&#xff01; 一、什么是金融行业 金融业是指经营金融商…

2023/12/12作业

思维导图 作业&#xff1a; 成果图 代码 #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { speechernew QTextToSpeech(this); ui->setupUi(this); //一直获取当前时间 idst…

用友 U8 Cloud upload.jsp 文件上传漏洞复现

0x01 产品简介 用友U8 Cloud 提供企业级云ERP整体解决方案,全面支持多组织业务协同,实现企业互联网资源连接。 U8 Cloud 亦是亚太地区成长型企业最广泛采用的云解决方案。 0x02 漏洞概述 用友U8 Cloud upload.jsp接口存在任意文件上传漏洞,攻击者可通过该漏洞上传木马,远…

基于ssm智能卤菜销售平台源码和论文

摘 要 随着互联网技术的高速发展&#xff0c;人们生活的各方面都受到互联网技术的影响。现在人们可以通过互联网技术就能实现不出家门就可以通过网络进行系统管理&#xff0c;交易等&#xff0c;而且过程简单、快捷。同样的&#xff0c;在人们的工作生活中&#xff0c;也就需要…

Keil 编译输出信息分析:Program size: Code, RO-data , RW-data, ZI-data

一般 MCU 包含的存储空间有&#xff1a;片内 Flash 与片内 RAM&#xff0c;RAM 相当于内存&#xff0c;Flash 相当于硬盘。编译器会将一个程序分类为好几个部分&#xff0c;分别存储在 MCU 不同的存储区。 如图所示&#xff0c;在Keil中编译工程成功后&#xff0c;在下面的Bul…

2023-12-05 Qt学习总结9

点击 <C 语言编程核心突破> 快速C语言入门 Qt学习总结 前言二十五 QFile文件操作总结 前言 要解决问题: 学习qt最核心知识, 多一个都不学. 二十五 QFile文件操作 QFile是Qt提供的文件读写类&#xff0c;支持对文件进行读写、复制、重命名、删除等操作。常用C函数如下&…