您当前的位置:首页 > 电脑百科 > 数据库 > Redis

看完Redis缓存穿透、缓存击穿、缓存雪崩来吊打面试官!

时间:2023-12-06 13:55:49  来源:微信公众号  作者:小王博客基地

一、前言

redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。」

Redis在缓存应用中还是很广泛的,项目中也经常使用。基本上面试中肯定都会问到,总结一下增强记忆哈!

在享受缓存带来的好处的同时,当然要防止这些不好的方面。

下面我们一起来看看这三种情况的产生原因和解决方案!

「总结: 这三种情况都是在大量请求来的时候,Redis没有命中,请求直接打到数据库,从而导致数据库挂掉!」

Redis缓存简图:

看完Redis缓存穿透、缓存击穿、缓存雪崩来吊打面试官!

二、缓存穿透

1、产生原因

「大量请求的 key 是不合理的,缓存中根本不存在(数据库中一般也不存在),导致这些请求绕过缓存直接访问数据库,给数据库造成了巨大的压力,随时可能宕机。」

  • 恶意查询,如查询id为负数等等。
  • key过期,突然来了大量请求时。
  • key没有提前预热,突然来了大量请求时。

2、解决方案

  • 设置缓存空值:查询数据库没有结果,将空值缓存,但必须设置一个合理的过期时间。
  • 布隆过滤器:是一种用于判断一个元素是否属于一个集合的数据结构。
  • 合理判断参数的范围:非负数等等。
  • 限制并发查询:保证只有一个线程去查询底层数据源,其他线程等待查询结果。

3、具体方案

「设置缓存空值:」

redis有一个配置,可以把从数据库查询出来为空的也缓存到Redis中,也可以自己在代码中写,顺便加上过期时间,也可以配置过期时间,这样是全局都是这个过期时间了,不太建议这样!

spring:
  cache: 
    redis:
      cache-null-value: true
      time-to-live: 30s

「限制并发查询:」

@Cacheable(value={"category"},key = "#root.methodName",sync = true)

sync = true:表示多个线程在尝试获取缓存数据的时候会被阻塞,直到第一个线程从数据库加载数据并放入缓存后,其他线程才能获取到缓存中的数据。这样可以避免多个线程同时查询底层数据库,减轻数据库负载,但会降低并发性能。 默认为false,不开启

「布隆过滤器:」

布隆过滤器(Bloom Filter)是一种用于判断一个元素是否属于一个集合的数据结构。它的主要特点是高效地判断元素是否存在于集合中,且具有空间和时间效率高的优点。布隆过滤器不会存储实际的数据,而是通过一系列的哈希函数和位数组来判断元素的存在。

看完Redis缓存穿透、缓存击穿、缓存雪崩来吊打面试官!

「当布隆过滤器判断元素不存在时,元素一定不存在,元素存在时,元素不一定存在!」

是不是有点绕,我们在详细说一下:

布隆过滤器有一定的假阳性概率,即在判断元素存在时,有可能出现错误的结果。这是因为多个元素可能产生相同的哈希值,导致位数组中的位被设置为1。

「布隆过滤器一旦添加了元素,就不能删除,因为删除元素会影响其他元素的判断结果。」

一般引入guava中的BloomFilter来实现布隆过滤器!如果喜欢用Hutool,也是有实现的!

下面小编给大家简单的写个demo,大家感受一下!

「引入依赖」

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

「配置布隆过滤器」

/**
 * @author wangzhenjun
 * @date 2023/11/7 17:08
 */
@Configuration
public class BloomFilterConfig {

    // 预期插入的元素个数,从配置文件里拿
    private static final Integer EXPECTED_INSERTIONS = 100000;

    // 期望的误判率,值越低,布隆过滤器计算时间越长,从配置文件里拿
    private static final Double FPP = 0.03;

    @Bean
    public BloomFilter<String> bloomFilter(){
        BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), EXPECTED_INSERTIONS,FPP);
        return filter;
    }

}

「简单测试」

为了简单,直接写在启动类上了,大家不要学哈!

@EnableAsync
@MApperScan("com.example.demonew.demo.mapper")
@EnableTransactionManagement
@SpringBootApplication
public class DemoNewApplication {

    @Autowired
    private BloomFilter bloomFilter;

    public static void mAIn(String[] args) {
        SpringApplication.run(DemoNewApplication.class, args);

    }

    @PostConstruct
    public void init(){
        bloomFilter.put("123");
        boolean b = bloomFilter.mightContain("123");
        System.out.println("是否存在:" + b);
    }

}

看完Redis缓存穿透、缓存击穿、缓存雪崩来吊打面试官!

三、缓存击穿

1、产生原因

「缓存击穿是指当缓存中某个热点key刚刚过期(一般和缓存穿透区别在于热点数据存在于数据库中),在热点数据重新放入缓存之前,瞬间大量的请求绕过缓存,直接打到数据库,数据库随时宕机!」

并发访问热点key:多个并发请求同时访问相同的缓存键

缓存策略问题:设置了过于短的缓存过期时间,容易导致缓存频繁失效。

「一般出现在秒杀中,秒杀都会提前预热,设置key直到活动结束才会过期!」

2、解决方案

  • 缓存预热:系统启动或缓存过期之前,预先加载常用数据到缓存中。
  • key永不过期或者使用期间内不过期。
  • 限制并发查询:保证只有一个线程去查询底层数据源,其他线程等待查询结果。
  • 接口限流、熔断、降级。

3、具体方案

「缓存预热:」

在项目启动时,或者定时任务扫描进行预热!

「限制并发查询:」

@Cacheable(value={"category"},key = "#root.methodName",sync = true)、

详细解释上面已经说过了哈!

「接口限流、熔断、降级」

可以引入:Sentinel来帮助我们更好的限流、熔断、降级,这里就不详细演示了!

四、缓存雪崩

1、产生原因

「缓存雪崩是指缓存中大量key到了过期时间,导致大量的请求直接打到数据库上,数据库随时宕机!」

  • redis服务宕机:redis挂了,所有的key都无法访问
  • 批量设置大量key相同的过期时间

2、解决方案

  • redis搭建集群或者哨兵。
  • 随机设置缓存的失效时间(合理范围内的随机时间),或者用不过期(不建议)。
  • 限制并发查询:保证只有一个线程去查询底层数据源,其他线程等待查询结果。
  • 接口限流、熔断、降级。
  • 多级缓存

「这个多级缓存,能不加不加,加了就需要考虑一致性,增加很多复杂度!」

其实缓存击穿和缓存雪崩是很相似的,解决方案,大家也可以看出来很多相同的!这就引出下一个经常问到的问题:

3、具体解决方案

关于Redis的哨兵搭建可以看一下之前写的文章,这里就不演示了!

关于多级缓存,可以引入本地缓存Caffeine。

4、补充

「缓存击穿和缓存雪崩的区别?」

缓存击穿是缓存中某个热点key不存在了,缓存雪崩是缓存中大量或者所有key都不存在了

他俩的根本区别在于一个是单个key,一个是多个甚至全部key!

五、缓存污染

这里补充一下,关于缓存污染的吧!

1、产生原因

缓存污染指缓存中一些访问次数很少的key,甚至只有一次!但是缓存中会存储着,占用内存空间。随着时间越来越久,内存很快被占满,就需要开启淘汰策略去额外处理这些多余的key,影响redis性能。

2、解决方案

  • 对与key进行监控,不常用key不需要加入缓存。
  • 分析出key访问次数很少,设置过期时间短一些。
  • 配置淘汰策略:LRU(最近最少使用)淘汰策略。

最主要还是要把不常用的key找到,后面不在加入缓存,从根本上解决!

还会出现在多个节点之间的数据同步出现数据不统一时产生,这个东西不好避免,因为Redis 是AP(可用性和分区容忍性),在多节点时,一半以上同步完成时,就认为同步成功了!

六、缓存一致性

引入了缓存就必须要保持缓存的一致性,不然加了缓存没有任何意义!

网上关于缓存一致性的文章很多,什么延迟双删等等。

这些都不如阿里Canal,这个是通过监听MySQL的Bin Log日志,来去更新到缓存中!

七、总结

今天我们深入具体的讨论了Redis缓存穿透、缓存击穿、缓存雪崩的产生原因和解决方案,补充了缓存污染和缓存一致性。

是不是有了深刻的印象,这些东西在企业级还是挺常见的,在面试过程中更加常见。 相信大家从头看到尾,对于面试肯定是没有任何问题的。

在企业级应用中,一定要具体情况具体分析,不要盲目照搬,不一定适合你们的需求。



Tags:Redis   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Redis 不再 “开源”,未来采用 SSPLv1 和 RSALv2 许可证
Redis 官方于21日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause...【详细内容】
2024-03-27  Search: Redis  点击:(11)  评论:(0)  加入收藏
Redis“叛逃”开源,得罪了几乎所有人
内存数据库供应商Redis近日在开源界砸下了一块“巨石”。Redis即将转向双许可模式,并实施更为严格的许可条款。官方对此次变更的公告直截了当:从Redis 7.4版本开始,Redis将在Re...【详细内容】
2024-03-25  Search: Redis  点击:(9)  评论:(0)  加入收藏
如何使用 Redis 实现消息队列
Redis不仅是一个强大的内存数据存储系统,它还可以用作一个高效的消息队列。消息队列是应用程序间或应用程序内部进行异步通信的一种方式,它允许数据生产者将消息放入队列中,然...【详细内容】
2024-03-22  Search: Redis  点击:(17)  评论:(0)  加入收藏
Redis不再 “开源”
Redis 官方今日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause 开...【详细内容】
2024-03-21  Search: Redis  点击:(8)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  Search: Redis  点击:(47)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  Search: Redis  点击:(39)  评论:(0)  加入收藏
工作中Redis有哪些好用的运维工具
工作中使用 Redis 时,如果大家公司没有专业运维,可能开发人员就会面临这些运维的工作,包括 Redis 的运行状态监控,数据迁移,主从集群、切片集群的部署和运维等等。本文我就从这三...【详细内容】
2024-02-06  Search: Redis  点击:(55)  评论:(0)  加入收藏
深入Go底层原理,重写Redis中间件实战
Go语言以其简洁、高效和并发性能而闻名,深入了解其底层原理可以帮助我们更好地利用其优势。在本文中,我们将探讨如何深入Go底层原理,以及如何利用这些知识重新实现一个简单的Re...【详细内容】
2024-01-25  Search: Redis  点击:(66)  评论:(0)  加入收藏
批量执行Redis命令的四种方式!
前言在我们的印象中Redis命令好像都是一个个单条进行执行的,如果有人问你如何批量执行Redis命令,你能回答的上吗,或者说能答出几种方式呢?最容易想到的是Redis的一些批量命令,例...【详细内容】
2024-01-17  Search: Redis  点击:(57)  评论:(0)  加入收藏
Redis 实现多规则限流的思考与实践
市面上很多介绍redis如何实现限流的,但是大部分都有一个缺点,就是只能实现单一的限流,比如1分钟访问1次或者60分钟访问10次这种,但是如果想一个接口两种规则都需要满足呢,我们的...【详细内容】
2024-01-03  Search: Redis  点击:(109)  评论:(0)  加入收藏
▌简易百科推荐
Redis 不再 “开源”,未来采用 SSPLv1 和 RSALv2 许可证
Redis 官方于21日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause...【详细内容】
2024-03-27  dbaplus社群    Tags:Redis   点击:(11)  评论:(0)  加入收藏
Redis“叛逃”开源,得罪了几乎所有人
内存数据库供应商Redis近日在开源界砸下了一块“巨石”。Redis即将转向双许可模式,并实施更为严格的许可条款。官方对此次变更的公告直截了当:从Redis 7.4版本开始,Redis将在Re...【详细内容】
2024-03-25    51CTO  Tags:Redis   点击:(9)  评论:(0)  加入收藏
如何使用 Redis 实现消息队列
Redis不仅是一个强大的内存数据存储系统,它还可以用作一个高效的消息队列。消息队列是应用程序间或应用程序内部进行异步通信的一种方式,它允许数据生产者将消息放入队列中,然...【详细内容】
2024-03-22  后端Q  微信公众号  Tags:Redis   点击:(17)  评论:(0)  加入收藏
Redis不再 “开源”
Redis 官方今日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause 开...【详细内容】
2024-03-21  OSC开源社区    Tags:Redis   点击:(8)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  编程技术汇    Tags:Redis   点击:(47)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  楼仔  微信公众号  Tags:Redis   点击:(39)  评论:(0)  加入收藏
工作中Redis有哪些好用的运维工具
工作中使用 Redis 时,如果大家公司没有专业运维,可能开发人员就会面临这些运维的工作,包括 Redis 的运行状态监控,数据迁移,主从集群、切片集群的部署和运维等等。本文我就从这三...【详细内容】
2024-02-06  waynaqua    Tags:Redis   点击:(55)  评论:(0)  加入收藏
批量执行Redis命令的四种方式!
前言在我们的印象中Redis命令好像都是一个个单条进行执行的,如果有人问你如何批量执行Redis命令,你能回答的上吗,或者说能答出几种方式呢?最容易想到的是Redis的一些批量命令,例...【详细内容】
2024-01-17  小许code  微信公众号  Tags:Redis命令   点击:(57)  评论:(0)  加入收藏
Redis 实现多规则限流的思考与实践
市面上很多介绍redis如何实现限流的,但是大部分都有一个缺点,就是只能实现单一的限流,比如1分钟访问1次或者60分钟访问10次这种,但是如果想一个接口两种规则都需要满足呢,我们的...【详细内容】
2024-01-03  架构精进之路  微信公众号  Tags:Redis   点击:(109)  评论:(0)  加入收藏
一站式Redis解决方案
Redis是一个高效的内存数据库,它支持包括String、List、Set、SortedSet和Hash等数据类型的存储,在Redis中通常根据数据的key查询其value值,Redis没有模糊条件查询,在面对一些需...【详细内容】
2024-01-01  大雷家吃饭    Tags:Redis   点击:(66)  评论:(0)  加入收藏
站内最新
站内热门
站内头条