面试官:谈关于缓存穿透+击穿+雪崩,热点数据失效问题的解决方案

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 当我们查询一条数据时,先去查询缓存,如果缓存有就直接返回,如果没有就去查询数据库,然后返回。这种情况下就可能出现下面的一些现象。2.缓存穿透

1.我们使用缓存时的业务流程大概为:

当我们查询一条数据时,先去查询缓存,如果缓存有就直接返回,如果没有就去查询数据库,然后返回。这种情况下就可能出现下面的一些现象。

2.缓存穿透

2.1什么是缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

2.2缓存穿透带来的问题

试想一下,如果有黑客对你的系统进行攻击,拿一个不存在的id去查询数据,会产生大量的请求到你的数据库去查询,可能会导致你的数据库由于压力过大而宕掉。

2.3解决的办法

2.3.1缓存空值

之所以会发生穿透,就是因为缓存中没有储存这些空数据的key。从而导致每次查询都到数据库去了。

那么我们就可以为这些key对应的值设置为null丢到缓存里面去。后面出现查询这个key的请求的时候直接返回null。

这样就不用再到数据库中去走一圈了,但是别忘了设置过期时间。

缓存空对象会有两个问题:

  • 第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。
  • 第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

2.3.2用布隆过滤器BloomFilter

BloomFilter类似于一个hbase set用来判断某个元素(key)是否存在于某个集合中。

这种方式在大数据场景应用比较多,比如Hbase中使用它去判断数据是否在磁盘上。还有在爬虫场景判断url是否已经被爬取过。

这种方案可以加在第一种方案中,在缓存之前加一层BloomFilter,在查询的时候先去BloomFilter去查询key是否存在,如果不存在就直接返回,存在再去查缓存-------->差数据库。

流程图如下:

2.4如何选择

针对于一些恶意攻击,攻击带来大量key是不存在的,那么我们采用第一种方案就会缓存大量不存在的数据。此时我们采用第一种方案就不合适了,我们完全可以先使用第二种方案过滤掉这些key。

针对这些key异常多,请求多,重复率比较低的数据,我们就没有必要进行缓存,使用第二种方案直接过滤掉。

而对于空数据的key有限的,重复率比较高的,我们则可以采用第一种方式进行缓存。

3.缓存击穿

3.1什么是缓存击穿

缓存击穿是我们使用缓存可能遇到的第二个问题。

在平时高并发的系统中,大量的请求同时查询一个key时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去,这种现象我们称为缓存击穿。

3.2会带来什么问题

会造成某一时刻数据请求量过大,压力剧增。

3.3如何解决

上面现象是多个线程同时去查询数据库的这一条数据,那么我们可以在第一个查询数据的请求上使用一个互斥锁来锁住它。(如果是单机,可以用synchronized或者lock来处理,如果是分布式环境可以用分布式锁就可以了(分布式锁,可以用memcache的add, redis的setnx, zookeeper的添加节点操作))

其他线程走到这一步拿不到锁就等着,等待第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有了缓存,就直接走缓存。

4.缓存雪崩

4.1什么是缓存雪崩

缓存雪崩的情况是指:当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到数据库上面,结果就是数据库挂掉。

4.2解决办法

4.2.1雪崩前:使用集群缓存,保证缓存服务的高可用

这种方案就是在发生雪崩前对缓存集群,实现高可用,如果是使用Redis,可以使用(主从 + 哨兵),Redis Cluster来避免Redis全盘崩溃的情况。

4.2.2雪崩中:ehcache本地缓存 + Hystrix限流 & 降级,避免MySQl被打死

使用ehcache本地缓存的目的也是考虑Redis Cluster完全不可用的时候,ehcache本地缓存还能够支撑一阵。

使用Hystrix进行限流 & 降级,比如一秒来了5000个请求,我们可以设置假设一秒只能有2000个请求可以通过这个组件,那么其他剩余的3000请求就会走限流逻辑。

然后去调用我们自己开发的降级组件(降级),比如设置的一些默认值等等之类的。以此来保护最后的MySQl不会被大量的请求打死。

4.2.3雪崩后:开启Redis持久化,尽快恢复缓存集群。

5.解决热点数据集中失效问题

我们在设置缓存的时候,一般会给缓存设置一个失效的时间,过了这个时间,缓存就失效了。

对于一些热点数据来说,当缓存失效后会存在大量的请求到数据库上来,从而可能导致数据库崩溃的情况。

5.1解决办法

5.1.1设置不同的失效时间

为了避免这些热点数据集体失效,那么我们在设置缓存过期时间的时侯,让他们失效的时间错开。比如我们可以在原有的失效时间基础上增加一个随机值。

5.1.2互斥锁

结合上面的击穿情况,在第一个请求去查询数据库的时候对它加一个互斥锁,其余的查询请求都会被阻塞住,直到锁被释放,从而保护数据库。

但是也是由于它会阻塞其他线程,此时系统的吞吐量会下降。需要结合实际业务去考虑。

本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
21天前
|
缓存 NoSQL 数据库
缓存穿透、缓存击穿和缓存雪崩及其解决方案
在现代应用中,缓存是提升性能的关键技术之一。然而,缓存系统也可能遇到一系列问题,如缓存穿透、缓存击穿和缓存雪崩。这些问题可能导致数据库压力过大,甚至系统崩溃。本文将探讨这些问题及其解决方案。
|
1月前
|
SQL 缓存 关系型数据库
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴因未能系统梳理MySQL缓存机制而在美团面试中失利。为此,尼恩对MySQL的缓存机制进行了系统化梳理,包括一级缓存(InnoDB缓存)和二级缓存(查询缓存)。同时,他还将这些知识点整理进《尼恩Java面试宝典PDF》V175版本,帮助大家提升技术水平,顺利通过面试。更多技术资料请关注公号【技术自由圈】。
美团面试:Mysql 有几级缓存? 每一级缓存,具体是什么?
|
29天前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
39 5
|
1月前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
71 10
|
1月前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
55 5
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
1月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
1月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
57 4