还不懂缓存穿透?Redis缓存穿透深度剖析

🎈个人公众号:🎈 :✨✨✨ 可为编程✨ 🍟🍟
🔑个人信条:🔑 知足知不足 有为有不为 为与不为皆为可为🌵
🍉本篇简介:🍉本篇记录Redis缓存穿透深度剖析命令操作,如有出入还望指正。

当系统中引入redis缓存后,一个请求进来后,会先从redis缓存中查询,缓存有就直接返回,缓存中没有就去db中查询,db中如果有就会将其丢到缓存中,但是有些key对应更多数据在db中并不存在,或者缓存大批量失效了,每次针对此次key的请求从缓存中取不到,请求都会压到db,从而可能压垮db。因此本篇就针对Redis缓存使用中存在的问题进行梳理,针对问题按照代码模拟现实场景并给出解决方案。

概述

当系统中引入redis缓存后,一个请求进来后,会先从redis缓存中查询,缓存有就直接返回,缓存中没有就去db中查询,db中如果有就会将其丢到缓存中,但是有些key对应更多数据在db中并不存在,或者缓存大批量失效了,每次针对此次key的请求从缓存中取不到,请求都会压到db,从而可能压垮db。因此本篇就针对Redis缓存使用中存在的问题进行梳理,针对问题按照代码模拟现实场景并给出解决方案。

关注公众号【可为编程】回复【加群】进入微信交流群一起学习!!!

缓存穿透

缓存穿透定义

穿透,顾名思义穿透缓存肯定是到数据库了,肯定是查询数据库不存在的数据,因为如果数据库中存在,查询一遍就存入到缓存了,就不会再次和数据库进行IO操作了。正因为数据库没有数据,导致每次请求都要到数据库中,失去了缓存的意义。总结一下造成缓存穿透的条件有:
1、数据库中没有符合请求条件的数据
2、请求穿透缓存频繁请求数据库
3、每次查询的值都不在redis中

缓存穿透场景

Redis起到保护数据库的作用,提升查询效率,如果连数据库都不存在对应数据,同时也就不会写入到Redis中,频繁查询就会和数据库进行频繁IO操作。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用大量此类攻击可能压垮数据库。那么有人会想了,可不可以做个校验呢?如果缓存中不存在用户信息,那么就存一下该用户信息,保证不到数据库不就不会压垮数据库了嘛,确实是这样。
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!

缓存穿透场景模拟

下面我根据现实的场景模拟一下,首先先去查询缓存,如果缓存不存在就去检索数据库,存在即返回。
Controller

@GetMapping("list")
    public String list(@Param("id") Integer id) {
        String re = redisUtils.get("test");
        //2. 缓存中没有数据,查询数据库
        System.out.println("缓存命中...");
        if (StringUtils.isEmpty(re)) {
            //2. 缓存中没有数据,查询数据款
            System.out.println("缓存不命中...查询数据库");
            Test test = testService.queryTest(id);
            return JSON.toJSONString(test);
        }
        System.out.println(re);
        return re;
    }

service

 public Test queryTest(Integer id) {
        Test row = testMapper.queryTest(id);
        System.out.println("查询数据库");
        return row;
    }

我们请求参数id传一个数据库不存在该条数据的id,肯定直接打到数据库。
在这里插入图片描述
数据库中也没有该数据,如果处于高并发情况下这种场景直接造成数据库宕机,因此我们可以将查询出来的null结果存入到缓存,只需要第一次查询的时候检索数据库,后面直接命中缓存返回结果。修改service。

public Test queryTest(Integer id) {
        Test row = testMapper.queryTest(id);
        System.out.println("查询数据库");
        //查询数据库后将对象存入缓存
        redisUtils.set("test", JSON.toJSONString(row));
        redisUtils.expire("test", 30, TimeUnit.MINUTES);
        return row;
    }

在这里插入图片描述
第一次查询数据库并存入缓存,第二次直接查询缓存,看似没有问题,逻辑很合理,但是在高并发的场景下就会出问题了,我们采用Jmater进行压力测试,模拟100个并发请求同时请求查询接口。
在这里插入图片描述
因为多线程场景下存在线程抢占机制,都在查询缓存然后查询数据库,第一个线程来了,看到缓存没有,就去查询数据库,第二个线程来了发现缓存还没有,继续查询数据库,当在查询出来数据与存入缓存环节的空隙时间内,多个请求已经打到数据库了,所以我们要保证并发情况下的操作原子性。由于springboot所有的组件都是单例的,即使有批量请求也让他访问查询和存入缓存的操作是使用同一把锁,所以可以使用synchronized (this)来加锁,第一个请求来时获取锁,查询数据库,在查询之前再次确认下缓存中是否有数据,如果没有则从数据库中查询,获取到数据后存入缓存中。
修改service方法实现

public Test queryTest(Integer id) {
        //只要是同一把锁就可以锁住所有的线程
        //1. synchronized (this): springboot所有的组件都是单例的,即使有批量请求也是使用同一把锁
        synchronized (this) {
            //关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
            //得到锁以后,应该先去缓存中确定一次,如果没有再进行查询
            String test = redisUtils.get("test");
            if (!StringUtils.isEmpty(test)) {
                //缓存不为空直接返回
                return (Test) JSON.toJSON(test);
            }
            //将数据库的多次查询变为一次
            Test row = testMapper.queryTest(id);
            System.out.println("查询数据库");
            //查询数据库后将对象存入缓存
            redisUtils.set("test", JSON.toJSONString(row));
            redisUtils.expire("test", 30, TimeUnit.MINUTES);
            return row;
        }
    }

我们再次执行之后就发现不会出现刚才那种场景了,只查询了一次数据库,其他请求都没有打到数据库上面。
在这里插入图片描述

缓存不命中...
缓存不命中...
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
==> Parameters: 5(Integer)
从缓存中获取数据时出现异常,key:test,value:null
java.lang.NullPointerException: null
<==      Total: 0
查询数据库
缓存命中...
null
缓存不命中...
缓存不命中...
缓存不命中...
缓存不命中...
缓存命中...
null
缓存命中...
null

多次执行的结果是不一样的,线程的优先级和时间片分配可能影响线程的执行顺序和时长,进而影响多线程程序的结果。在实际的生产环境中我们主要是采用消息中间件来接受并发请求,按顺序逐一进行处理,同时引入多线程提高任务执行效率。
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!

缓存穿透解决方案

可以在缓存中存一个空字符串,或者其他特殊字符串用于标识该条为空的数据,然后当应用拿到这个特殊字符串的时候表示数据库没有值,就没必要再去查询数据库了。但是存特殊字符的办法只适用于重复查询同一个不存在的值的情况,如果每次请求,ID都是可变的,并假设ID符合规则,但是每次变化的值都不存在于数据库中,那请求还是会打到数据库中。伪代码如下:

while(true){
  where id = random();
}

所以总结一下几个比较好的解决方案:
关注公众号【可为编程】回复【面试】领取年度最新面试题大全!!!
1、对空值缓存
如果一个查询返回的数据为空(不管数据库是否存在),我们仍然把这个结果(null)进行缓存,给其设置一个很短的过期时间,最长不超过五分钟。不然新增了这条数据后,查询还是查不到,保证在后续新增之后不会影响数据查询。
2、设置可访问的名单(白名单)
使用redis中的bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问的id不在bitmaps里面,则进行拦截,不允许访问

(3)采用布隆过滤器
布隆过滤器(Bloom Filter)是1970年由布隆提出的,它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。

布隆过滤器可以用于检测一个元素是否在一个集合中,它的优点是空间效率和查询的时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。后面会单独对其进行介绍。

(4)进行实时监控
当发现redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制对其提供服务(比如:IP黑名单)

今天写太慢了,明天争取将缓存雪崩和缓存击穿一起写出来,重在学习,重在消化。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 项目配置文件出现乱码的解决方法

如下图&#xff0c;我们 Spring Boot 项目的配置文件 application.properties 可能会出现如下的乱码问题&#xff1a; 我们写注解的时候是正常的&#xff0c;但是下次启动项目就出现了乱码&#xff0c;这个是字符集设置的问题 解决方法 1.点击 File 选择 Settings 2.搜索 enco…

activiti工作流 定义 TaskListener 无效

使用activiti 5.22 想全局定义任务监听器&#xff0c;结果试了多次发现没有效果。 最后看了看activiti的相关源码发现&#xff0c;流程定义里边没有处理 TaskListener 相关的操作&#xff0c;发现TaskListener 处理是在Task里边处理的&#xff0c;所以把TaskListener 定义在Ta…

python 扩展数据(补全缺失日期)

背景&#xff1a;有一时间序列数据&#xff0c;如下图&#xff0c;存在部分城市缺失一些日期的数据。目标&#xff1a;补齐缺失的日期数据&#xff08;本文完整的日期范围是2022.1.1-2022.1.5&#xff09;。 代码 # 补全缺失日期 min_date df[日期].min() max_date df[日期]…

617. 合并二叉树

617. 合并二叉树 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;_617合并二叉树_使用队列迭代_617合并二叉树_使用栈迭代 错误经验吸取 原题链接&#xff1a; 617. 合并二叉树 https://leetcode.cn/problems/merge-two-binary-trees/de…

Intellij Idea 断点小圆变成灰色怎么处理

场景1&#xff1a;变成了灰色实心圆 原因 断点变成灰色通常表示该断点处于失效状态。这可能是由于无意中点击了debug调试下方的“mute breakpoints”按钮导致的。 解决方案 依次点击设置小图标->View Options->Mute BreakPoints. 点击后 Mute BrakPoints左侧显示✔ 符号…

Redis基础——入门数据类型常用命令Java中操作Redis

这里写目录标题 1. 前言1.1 什么是Redis1.2 使用Redis能做什么 2. Redis入门2.1 Redis简介2.2 Redis下载与安装2.2.1 Redis下载2.2.2 Redis安装 2.3 Redis服务启动与停止2.4 Redis配置文件 3. Redis数据类型3.1 介绍3.2 Redis 5种常用数据类型 4. Redis常用命令4.1 字符串strin…

动起来,数据不散漏:上海迅软DSE助您解锁员工外带电脑信息安全新境界!

笔记本电脑作为企业数据泄密主要的途径之一&#xff0c;当员工携带着存放企业重要技术资料的笔记本在外办公时&#xff0c;很容易由于频繁的流动性让数据面临着丢失、恶意泄密等巨大风险&#xff0c;对此企事业单位需要通过一定的管理手段加以安全防护管控。 迅软DSE解决方案 一…

2023机器人灵巧手的分类与商业化应用及未来市场规模分析报告

今天分享的是机器人系列深度研究报告&#xff1a;《2023机器人灵巧手的分类与商业化应用及未来市场规模分析报告》。 &#xff08;报告出品方&#xff1a;深度行业分析研究&#xff09; 报告共计&#xff1a;26页 1 灵巧手是人形机器人重要的运控交互部件&#xff0c;近年来海…

深入理解CSS变量:高级技巧和最佳实践

前言 CSS 变量是一项强大的功能&#xff0c;它可以帮助开发人员更好地组织和管理样式表。在本文中&#xff0c;我们将深入探讨 CSS 变量的高级技巧和最佳实践&#xff0c;通过学习如何使用变量作为计算值、媒体查询和动态更改等方面&#xff0c;你将能够更好地利用 CSS 变量的强…

机器视觉 AI 数据集制作

工业中&#xff0c;机器视觉物体分拣时&#xff0c;需要制作&#xff0c;数据集&#xff0c;那么&#xff0c;一般情况下&#xff0c;可以选择几个物体的几张图片&#xff0c;或者视频&#xff0c;将待识别的物体的掩模扣取出来&#xff0c;随机的贴在 传送带背景中&#xff0c…

【23真题】大题全原题的211!题源已定位!

今天分享的是23年长安大学814的信号与系统试题及解析。 本套试卷难度分析&#xff1a;22年长安大学814考研真题&#xff0c;我也发布过&#xff0c;若有需要&#xff0c;戳这里自取&#xff01;本套试题难度中等偏下&#xff0c;题量偏多&#xff0c;考察的知识点也是很常见的…

华为OD机试 - 围棋的气(Java JS Python C)

题目描述 围棋棋盘由纵横各19条线垂直相交组成,棋盘上一共19 x 19 = 361 个交点,对弈双方一方执白棋,一方执黑棋,落子时只能将棋子置于交点上。 “气”是围棋中很重要的一个概念,某个棋子有几口气,是指其上下左右方向四个相邻的交叉点中,有几个交叉点没有棋子,由此可…

Lazada测评怎么做?

国内电商行业的发展日趋激烈&#xff0c;卖家想要脱颖而出非常困难&#xff0c;许多卖家选择入驻跨境电商平台开店&#xff0c; 跨境电商平台吸引了许多卖家入驻&#xff0c;而最近有很多朋友在私信问我关于Lazada测评的一些事情 Lazada产品测评流程步骤 怎么测评 这个怎么测…

特斯拉开源 Roadster 文件随便用;微软 Copilot AI 技术开放或不对大陆开放丨 RTE 开发者日报 Vol.92

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

空间统计分析

一、实验名称&#xff1a; 空间统计分析 二、实验目的&#xff1a; 通过本实验练习&#xff0c;掌握空间统计分析的基本方法。 三、实验内容和要求&#xff1a; 实验内容&#xff1a; 利用ARCGIS软件相关分析工具及实验数据&#xff08;某城市各个社区的家庭平均年收入&a…

自动驾驶学习笔记(十二)——定位技术

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo Beta宣讲和线下沙龙》免费报名—>传送门 文章目录 前言 卫星定位 RTK定位 IMU定位 GNSS定…

卸载软件最最最彻底的工具——Uninstall Tool

卸载软件最最最彻底的工具——Uninstall Tool Uninstall Tool 是一款功能强大的专业卸载工具。针对一些普通卸载不彻底的问题&#xff0c;它可以做到最优&#xff0c;比如Matlab等软件的卸载难的问题也可以较好地解决。 它比 Windows 自带的“添加/删除程序”功能快 3 倍&…

MySQL数据库如何应对故障恢复与数据恢复回滚

一个最基本的数据库&#xff0c;应当可以做到以下几点 数据持久化&#xff0c;可以将数据保存到磁盘&#xff0c;服务重启数据依然存在。 可以按照某种关系存储数据&#xff0c;如果你用过IO流&#xff0c;那么你会发现整理数据也是一件复杂的事情。我是该追加写呢还是找到某条…

英语语法:连词or, and, if, unless怎么用?

连词or, and, if, unless怎么用&#xff1f;1. or conj. 或者&#xff0c;还是&#xff0c; 和&#xff0c; 否则用法&#xff1a;并列连词①当“或者&#xff0c;还是”讲时&#xff0c;用在选择疑问句中&#xff0c;是选择疑问句的标志例&#xff1a;Are you a teacher or a …

NX二次开发UF_CURVE_create_arc_center_radius 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_create_arc_center_radius Defined in: uf_curve.h int UF_CURVE_create_arc_center_radius(tag_t center, double radius, tag_t help_point, UF_CURVE_limit_p_t limit_p…