高级java每日一道面试题-2024年10月8日-数据库篇[Redis篇]-谈—谈缓存穿透、缓存击穿和缓存雪崩,以及解决办法?

如果有遗漏,评论区告诉我进行补充

面试官: 谈---谈缓存穿透、缓存击穿和缓存雪崩,以及解决办法?

我回答:

在分布式系统和高并发场景中,缓存是提高系统性能和响应速度的重要手段。然而,如果缓存使用不当,可能会遇到一些问题,如缓存穿透、缓存击穿和缓存雪崩。下面我将详细解释这些问题以及相应的解决办法。

一、缓存穿透

定义

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。如果有恶意攻击者不断请求系统中不存在的数据,会导致短时间大量请求落在数据库上,造成数据库压力过大,甚至导致数据库承受不住而崩溃。

解决办法

  1. 接口校验:在接口层增加校验,如用户鉴权校验,对id做基础校验,id小于等于0的直接拦截。也可以在缓存层和数据库层都添加一些校验措施,例如检查请求的IP地址、User-Agent等信息,如果发现异常,则可以拒绝请求,防止缓存穿透。
  2. 使用布隆过滤器:布隆过滤器是一种概率型数据结构,可以用来判断一个元素是否在一个集合中。它类似于一个哈希算法,能够减少查询的次数,降低数据库的压力。
  3. 设置空值缓存:对于不存在的数据,可以设置一个默认值,如当查询不存在的数据时,返回这个默认值,而不是直接穿透缓存。也可以将key-value对写为key-null,并设置一个较短的过期时间(如30秒)。这样可以防止攻击用户反复用同一个id暴力攻击。
  4. 增加缓存更新频率:对于一些不常用的数据,可以增加其缓存更新频率,使得这些数据更快地过期,减少缓存穿透的可能性。
  5. IP限流:对频繁访问不存在数据的IP进行限流,防止恶意攻击。

二、缓存击穿

定义

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,导致数据库压力瞬间增大。

解决办法

  1. 设置热点数据不过期:对于经常被访问的热点数据,可以设置其缓存永不过期,从而避免缓存击穿的问题。
  2. 使用互斥锁:当缓存中不存在数据时,可以使用锁机制(如对key加锁),一次只允许一个线程去访问数据库,获取到数据后,马上更新缓存。这样可以避免大量并发请求同时冲击数据库。
  3. 设置逻辑过期时间:给缓存数据设置一个逻辑过期时间,而不是完全依赖于实际的缓存过期策略。当数据被访问时,先检查数据是否已经逻辑过期,如果是,则异步或在当前线程中更新缓存,同时返回旧数据给客户端。
  4. 延时更新:在缓存数据过期后,设置一个较短的过期时间,并在这个时间段内不断刷新缓存,直到数据从数据库中重新加载到缓存中。

三、缓存雪崩

定义

缓存雪崩是指缓存中大批量数据同时过期,而查询量又大,导致这些请求都落在数据库上,使得数据库层压力巨大,甚至宕机。

解决办法

  1. 分散过期时间:尽量让缓存中的数据过期时间分散一些,避免大量数据同时过期。
  2. 使用互斥锁或队列:在缓存失效时,可以设置一个短暂的锁定时间或队列,只允许一个请求查询数据库并刷新缓存,其他请求等待锁释放或队列处理后再读取缓存。
  3. 搭建缓存集群:为了防止单个缓存节点宕机导致雪崩,可以搭建缓存集群,提高缓存的容灾性。如 Redis Sentinel 或者 Redis Cluster,当某个缓存节点宕机时,其他节点可以继续提供服务,从而避免因为单个缓存服务器宕机导致的缓存雪崩问题。
  4. 设置热点数据不过期:类似于缓存击穿的处理方法,对于热点数据可以设置其永不过期。
  5. 实现本地缓存:在应用服务器本地维护一个小容量、高速缓存,作为远程缓存的补充,减少对外部缓存和数据库的依赖。
  6. 多级缓存:使用多级缓存策略,例如本地缓存 + 分布式缓存。即使分布式缓存失效,本地缓存也可以起到缓冲作用。如在本地缓存(如 Guava Cache 等)和分布式缓存(如 Redis)之间建立多级缓存。
  7. 限流与降级:通过限流技术控制到达数据库的请求数量,或者对某些非核心服务进行降级处理,优先保障系统的稳定性。
  8. 服务熔断:当检测到数据库负载过高时,触发服务熔断机制,暂时停止某些非核心服务的请求,以保护核心服务的正常运行。
  9. 异步更新:对于大规模更新操作,可以采用异步方式进行,避免短时间内大量数据失效。

总结

  • 缓存穿透:使用布隆过滤器或缓存空对象来减少无效请求对数据库的影响。
  • 缓存击穿:通过互斥锁、设置随机过期时间或永不过期来防止热点数据的集中访问。
  • 缓存雪崩:通过设置随机过期时间、多级缓存、限流与降级和服务熔断来分散失效时间和减轻数据库压力。

这些策略可以帮助你在高并发场景下更好地管理缓存,确保系统的稳定性和性能。

相关推荐
极客先躯1 个月前
高级java每日一道面试题-2024年11月09日-缓存中间件篇-Redis和Memecache有什么区别?
java·缓存·中间件·每日一道面试题·高级java·缓存中间件篇
雪碧聊技术1 个月前
Redis9:商户查询缓存3
数据库·缓存·缓存击穿·缓存雪崩
极客先躯2 个月前
高级java每日一道面试题-2024年10月27日-Redis篇-jedis和redisson有哪些区别?
分布式·redisson·jedis·redis篇·redis高级
极客先躯2 个月前
高级java每日一道面试题-2024年10月28日-RabbitMQ篇-RabbitMQ的使用场景有哪些?
java·rabbitmq·java-rabbitmq·面试题·异步·解耦·高级java
极客先躯2 个月前
高级java每日一道面试题-2024年10月26日-JVM篇-JVM的类加载机制是什么?
java·jvm·类加载·jvm篇·高级java
极客先躯2 个月前
高级java每日一道面试题-2024年10月20日-数据库篇[Redis篇]-Redis为什么是单线程的?
java·数据库·redis·数据库篇·数据库篇[redis篇]·redis篇·io复用
小璐乱撞xllz2 个月前
解决Redis缓存穿透(缓存空对象、布隆过滤器)
java·redis·分布式·后端·spring·缓存穿透
极客先躯2 个月前
高级java每日一道面试题-2024年10月22日-JVM篇-JVM堆栈概念,何时销毁对象?
java·开发语言·jvm·面试·垃圾回收·jvm篇·高级java
极客先躯2 个月前
mysql 有哪些架构类型?
数据库·mysql·架构·数据库篇
极客先躯2 个月前
高级java每日一道面试题-2024年10月12日-Web篇-http,servlet,tomcat 之间是什么关系?
java·前端·http·servlet·tomcat·web篇·高级java