redis的缓存穿透、击穿、雪崩以及实用解决方案
今天来聊聊redis的缓存穿透、击穿、雪崩以及解决方案,其中解决方案包括类似于布隆过滤器这种网上一搜一大片但是实际生产部署有一定复杂度的,也有基于spring注解通过一行代码就能解决的,其中各有优劣,咱们根据实际需要选型;
接下来会从穿透、击穿、雪崩的基本概念、各种问题对应的解决方案以及方案的具体实施来一一介绍
缓存穿透
概念
- 缓存穿透指某一特定时间批量请求打进来并访问了缓存和数据库都没有的key,此时会直接穿透缓存直达数据库,从而造成数据库瞬时压力倍增导致响应速度下降甚至崩溃的风险;
解决方案
一、通过布隆过滤器解决
原理:将所有需要缓存的key通过hash算法全部放到布隆过滤器将对应下标对应的值置成1,这样当请求进来时先去布隆过滤器里找,发现对应index的key是1则去缓存拿数据为0则直接返回,这样就避免了去数据库查询
优缺点:布隆过滤器底层通过redis的bitMap实现是基于位的操作,所以效率高;但是需要提前将key存入过滤器,这大大增加了前置成本;并且key到index的映射通过hash算法,那么必然会出现hash碰撞的问题;
二、通过key-null
- 原理:当请求进来从数据库查询回来的值为空时,将对应的null值也存入redis,这样下次请求时redis里已经有数据了就不会再怼到数据库了
- 优缺点:思路清晰,操作简单,但是极端情况下会有N多key在数据库和缓存中都没有,那这种实现就造成了redis里有过多的垃圾数据,浪费了内存空间
三、增强前置判断
- 原理:查询前在接口层做权限、逻辑校验,尽可能多的判断key的合法性
- 优缺点:使用成本低但并不足以规避掉缓存穿透的风险,所以建议只做附加的解决方案使用
缓存击穿
概念
- 缓存击穿指某一特定时间批量请求打进来对一个特定的值进行查询并访问了缓存中没有但是数据库里存在的key,此时会直接击穿缓存直达数据库,从而造成数据库瞬时压力倍增导致响应速度下降甚至崩溃的风险;需要注意的是,这里说的缓存中没有包含两层意思,一是缓存中本身没有,二十缓存中有但是过期了(少量热点key过期)
解决方案
一、设置key的过期时间随机
- 原理:在像redis批量设置key的时候尽量做到过期时间的随机性,以此避免某一时间会有批量key过期导致的缓存击穿
- 优缺点:虽然解决了缓存中同一时间批量key过期导致的击穿问题但是并不能解决缓存中压根就不存在key而造成的击穿
二、通过分布式锁解决
- 原理:在查询数据库的时候加一个分布式锁,使得某一特定时间内只有一个请求访问数据库,访问成功后将查询到的值缓存近redis,这样在下次访问时就不会造成击穿的现象了;
需要注意的是,针对非海量请求的业务这里加单机锁也问题不大,无非就是将同一时间只有一个请求到数据改成了同一时间只有集群数量的请求到数据库,问题应该也不大
- 优缺点:无论是缓存中本身就没有还是缓存中的key过期了使用加锁的方式都能解决缓存击穿的问题,但是却增加了加锁的成本
三、设置热点key永不过期
- 原理:针对热点key批量过期造成的穿透问题,将key设置成永不过期就能解决
- 优缺点:与一一样只能解决key过期造成的击穿不能解决缓存中没有key造成的击穿,并且热点key的确认也是门学问,并不总能保证设置的热点key不遗漏
四、将key部署在不同的实例
- 原理:针对集群部署的redis,将热点key分开部署也能避免过期造成的击穿问题
- 优缺点:只有集群才能使用,且也只能解决key过期造成的击穿问题,并不总能保证设置的热点key不遗漏
缓存雪崩
概念
- 与击穿相比雪崩表示过期或压根不存在的key是大量而不是一个或少量,导致大量请求落到数据库;
解决方案
一、通过设置过期时间随机来解决
- 设置key的时候加上随机过期时间,尽量减少同一时间过期key的数量;
二、设置锁
- 从缓存访问key开始就加锁,当缓存没有则去数据库查,查完塞入缓存最后释放锁;如果是单机应用则直接加虚拟机锁,集群部署的话则需使用分布式锁
小结
以上的实现方案可根据自己的业务需求灵活实现,其中个人认为布隆过滤器的落地相对复杂,成本也会更高,所以我们实际工作中并没有使用,而是用了基于spring-cache的@Cacheable注解,某种程度上可以说是一行代码解决了缓存击穿、穿透问题,下面说下@Cacheable注解
@Cacheable注解
一、介绍
- @Cacheable注解是一个spring3.1后引入的缓存技术,可通过在业务代码添加spring的缓存注解来实现缓存对象和方法的效果;而不用在业务代码里显示的进行set操作,大大方便了我们的日常开发
二、使用
- 1、在springboot的启动类添加
@EnableCaching注解开启缓存,否则下面的注解不会生效 - 2、直接上图,结合图来说明则一清二楚

说明
1、通过在方法上添加@Cacheable注解表示此方法需要走缓存,其中cacheNames的值加上方法的入参为唯一标识作为缓存中的key,而value则为方法的返回值;需要注意的是,当方法的入参和返回值是对象时则需要实现序列化(Serializable)接口
2、sync参数默认缺省值为false,表示是否是一个线程去数据库查询;所以当值为true时表示只有一个线程会打到数据库,这就解决了缓存击穿的问题;而针对缓存穿透,之前看到资料说需要添加spring.cache.redis.cache-null-values=true的配置才可以缓存空值,但我通过测试发现不论方法返回值是对象还是普通类型空值均可被缓存,我使用的spring版本是5.3.12;所以上面的代码也顺带解决了缓存穿透的问题
3、如果项目并发量小,不需要考虑穿透、击穿这些问题,可以直接写成@Cacheable("testCache")使sync缺省即可
三、总结
- 个人认为,针对@Cacheable已经足以解决实际开发中穿透、击穿的问题了;当然,如果假设一个集群有10000个实例,使用sync理论上也会有10000个请求同时抵达数据库从而影响数据库性能甚至崩溃,但是这种情况被我们碰到的情况很少,甚至可以说接触不到;但是如果真接触到了只能通过添加分布式锁去解决了
redis的缓存穿透、击穿、雪崩以及实用解决方案的更多相关文章
- Redis中几个简单的概念:缓存穿透/击穿/雪崩,别再被吓唬了
Redis中几个“看似”高大上的概念,经常有人提到,某些好事者喜欢死扣概念,实战没多少,嘴巴里冒出来的全是高大上的名词,个人一向鄙视概念党,呵呵! 其实这几个概念:缓存穿透/缓存击穿/缓存雪崩,有一个 ...
- NoSQL & Redis 介绍、缓存穿透 & 击穿 & 雪崩
1. NoSql 简介 2. Redis 简介 2.1 Redis 的起源 2.2 缓存过期 & 缓存淘汰 3. 缓存异常 1)缓存穿透 2)缓存击穿 3)缓存雪崩 4)总结 1. NoSQL ...
- 深入了解Redis(7)-缓存穿透,雪崩,击穿
redis作为一个内存数据库,在生产环境中使用会遇到许多问题,特别是像电商系统用来存储热点数据,容易出现缓存穿透,雪崩,击穿等问题.所以实际运用中需要做好前期处理工作. 一.缓存雪崩 1.概念 缓存雪 ...
- Redis作为缓存可能会出现的问题及解决方案
Redis是个大话题,只要是去面试Java开发,几乎必问.基础一点的问Redis是什么东西?用来做什么?Redis支持哪些数据类型?Redis的性能为什么那么好?复杂一点的就会问到缓存穿透.缓存击穿. ...
- Redis 17 缓存穿透 缓存击穿 缓存雪崩
参考源 https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0 版本 本文章基于 Redis 6.2.6 使用缓存的问题 ...
- redis:缓存穿透、缓存击穿、缓存雪崩
缓存穿透的解决方案(空标记) 缓存穿透是指,在数据存储系统中不存在的记录,不会被存储到缓存中.这种记录每次的查询流量都会穿透到数据存储层.在高流量的场景下,不断查询空结果会大量消耗数据查询服务的资源, ...
- 《Redis - 穿透/击穿/雪崩/集中失效》
一:什么是缓存穿透? - 定义 - 正常情况下,我们在理想的条件下去查询缓存数据都是存在的. - 那么请求去查询一条数据库中不存在的数据,也就是缓存和数据库都查询不到这条数据. - 所以请求每次都会打 ...
- Redis缓存穿透和雪崩
缓存穿透 用户想要查询一个数据 在redis缓存数据库中没有获取到 就会向后端的数据库中查询. 当用户很多 都去访问后端数据库的话,这就会给数据库带来很大的压力. 常见场景:秒杀活动 等 解决方法: ...
- Redis 穿透 & 击穿 & 雪崩
原文:https://www.cnblogs.com/binghe001/p/13661381.html 缓存穿透 如果在请求数据时,在缓存层和数据库层都没有找到符合条件的数据,也就是说,在缓存层和数 ...
随机推荐
- 蕞短鹭(artskjid) (⭐通信题/模拟⭐)
文章目录 题面(过于冗长,主要是对通信题的一些解释) 题解 1.通信题什么意思 2.此题题解 CODE 实现 题面(过于冗长,主要是对通信题的一些解释) 题解 1.通信题什么意思 并不是两个程序同时跑 ...
- 【Prometheus+Grafana系列】监控MySQL服务
前言 前面的一篇文章已经介绍了 docker-compose 搭建 Prometheus + Grafana 服务.当时实现了监控服务器指标数据,是通过 node_exporter.Prometheu ...
- 【java】学习路线12-内部类的使用事项
//内部类只能在其外部类当中使用//局部内部类:定义在方法里面//如果内部类和外部类有重名,就近原则在内部类中优先访问内部类.//如果想访问宿主类的同名成员,使用OuterClass.this.xxx ...
- Android Module配置C++支持
AndroidStudio提供了创建项目时选择C++支持的模板,但是新建Module的时候并没有C++模板, 要如何配置Module的C++支持呢? 虽然Module没有提供C++模板,但是我们可以手 ...
- iOS 苹果集成登录及苹果图标的制作要求
前言 如果要上架的应用集成了三方登录,那么在审核时,苹果会强制要求应用也要集成苹果登录.如果应用没有集成一般情况下都会被审核团队给打回来. 苹果集成登录 首先,你需要在开发者中心,找到你的应用,勾选上 ...
- KingbaseES 数据库Windows环境下注册失败分析
关键字: KingbaseES.Java.Register.服务注册 一.安装前准备 1.1 软件环境要求 金仓数据库管理系统KingbaseES V8.0支持微软Windows 7.Windows ...
- 微服务系列之网关(二) konga配置操作
1.konga核心对象 Kong 的四大核心对象:upstream,target,service,route.下面分别说: (1)upstream,字面意思上游,实际项目理解是对某一个服务的一个或者多 ...
- 使用spfa算法判断有没有负环
如果存在最短路径的边数大于等于点数,就有负环 给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数. 请你判断图中是否存在负权回路. 输入格式 第一行包含整数n和m. 接下来m行每行 ...
- Windows 10 索引设置
有时候想找一下电脑上的某个文件,但是只记得关键字不记得文件名的信息了.这个时候就会尝试在Windows的窗口中搜索.不过有时候明明文件存在,但是无法找到文件.这个时候就需要检查索引设置了.https: ...
- 《网页设计基础——CSS常用语法》
网页设计基础--CSS常用语法 一.注释: 例如: /* 在此处书写注释 */ 二.清除浏览器默认设置: 例如: *{ /* 全局声明 */ margin: 0; padding: ...