当前位置: 首页 > news >正文

【redis】缓存穿透、缓存击穿、缓存雪崩区别

缓存穿透、缓存击穿、缓存雪崩区别

这三个名字有点像, 尤其是缓存击穿和缓存穿透, 很多同学容易记混忘记, 而且面试经常被问到, 每次都要去看一遍, 非常难受, 本文将以大白话的形式解释这三个名词

1. 缓存穿透

穿透的意思: 一穿而过, 穿的是谁? 那肯定是redis, 穿过redis会发生什么? 回答这个问题之前我们要知道, redis作为缓存是用来干什么的. 当然是给数据库做缓存, 其除了提高性能的同时能避免数据库承受过多的压力, 那么很明显, 穿过redis后请求会到达数据库, 那么这叫缓存穿透吗, 其实并不是, 因为一般来讲正常的请求当然都是缓存中没有值, 请求数据库后把值缓存到redis中, 那么什么是缓存穿透及什么情况下会发生缓存穿透请继续往下看

什么是缓存穿透及什么情况下会发生缓存穿透: 首先正常系统出现缓存穿透的情况并不多见, 一般来看其是一种攻击手段, , 攻击者用缓存及数据库中不存在的值发动攻击请求, 由于redis中及数据库中都不存在这个值, 那么这个攻击请求就会绕开redis持续对数据库增加负载, 直到数据库崩溃, 其实这就叫缓存穿透

如何解决缓存穿透: 目前比较流行就是加布隆过滤器, 这玩意听着高大上其实是非常简单的东西, 自己使用hashSet也可以实现, 其原理就是事先把key放到布隆过滤器中, 然后收到请求的时候, 先查一下布隆过滤器中key是否存在, 如存在继续(查redis、查数据库), 如不存在则直接返回

布隆过滤器实现举例:

@Service
public class ProductService {@Autowiredprivate BloomFilter<String> productBloomFilter;@Autowiredprivate ProductRepository productRepository;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private static final String PRODUCT_CACHE_PREFIX = "product:";private static final long CACHE_EXPIRE_SECONDS = 3600; // 1小时/*** 初始化布隆过滤器*/@PostConstructpublic void initBloomFilter() {// 初始化时加载所有存在的ID到布隆过滤器List<Long> allIds = productRepository.findAllIds();allIds.forEach(id -> productBloomFilter.put(PRODUCT_CACHE_PREFIX + id));}/*** 布隆过滤器应对缓存穿透问题*/public Product getProductWithBloomFilter(Long id) {String cacheKey = PRODUCT_CACHE_PREFIX + id;// 1. 布隆过滤器检查if (!productBloomFilter.mightContain(cacheKey)) {throw new RuntimeException("Product not exists");}// 2. 正常缓存查询流程return getProductById(id);}public Product getProductById(Long id) {// 1. 先查Redis缓存String cacheKey = PRODUCT_CACHE_PREFIX + id;Product product = (Product) redisTemplate.opsForValue().get(cacheKey);if (product != null) {return product;}// 2. Redis没有则查数据库product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));// 3. 写入Redis并设置过期时间redisTemplate.opsForValue().set(cacheKey, product, CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS);return product;}
}

2. 缓存击穿

缓存击穿定义及发生情况: 某个热点key在缓存中过期失效的瞬间,同时有大量并发请求访问这个key,导致所有请求都直接打到数据库上,造成数据库瞬时压力激增甚至崩溃的现象
如何解决缓存击穿: 可以设置热点key永不过期, 或者使用提前预热的方式来解决缓存击穿问题, 也可以使用互斥锁只允许一个线程重建缓存

互斥锁的实现举例如下:

public Product getProductWithLock(Long id) {String cacheKey = "product:" + id;// 1. 先查缓存Product product = redis.get(cacheKey);if (product != null) {return product;}// 2. 获取分布式锁String lockKey = "lock:product:" + id;try {boolean locked = redisLock.tryLock(lockKey, 3, TimeUnit.SECONDS);if (!locked) {// 获取锁失败,短暂等待后重试Thread.sleep(100);return getProductWithLock(id);}// 3. Double Check(防止其他线程已经重建缓存)product = redis.get(cacheKey);if (product != null) {return product;}// 4. 查数据库product = db.getProduct(id);if (product == null) {// 应对缓存穿透,设置空值(如果已经设置布隆过滤器此步骤可省略)redis.set(cacheKey, new NullValue(), 5, TimeUnit.MINUTES);} else {// 5. 写入缓存redis.set(cacheKey, product, 1, TimeUnit.HOURS);}return product;} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);} finally {redisLock.unlock(lockKey);}
}

3.缓存雪崩

缓存雪崩字面意思: 雪崩顾名思义为大片大片的雪坍塌导致, 那么缓存雪崩也就是大面积的缓存数据过期, 导致多个请求突然打到数据库中, 导致数据库崩溃所致
**缓存雪崩什么情况下会发生: ** Redis缓存数据批量过期或Redis宕机

如何解决缓存雪崩: 一般来说避免多个key设置同一个过期时间, 对每个key设置差异化过期时间

当然这三个问题也有其他响应解决办法, 本文意在说明三个名词的区别及方便大家记忆其他不在赘述, 感谢大家观看 !

http://www.dtcms.com/a/298212.html

相关文章:

  • Java学习第七十三部分——Redis
  • 前端面试问题
  • 安卓小说阅读软件推荐
  • 深入解析HBase如何保证强一致性:WAL日志与MVCC机制
  • [尚庭公寓]14-找房模块
  • 手写A2C(FrozenLake环境)
  • 直播美颜SDK动态贴纸模块开发指南:从人脸关键点识别到3D贴合
  • kiro的介绍和安装
  • 7.文件操作:让程序读写文件 [特殊字符]
  • CentOS 7.9 + GCC9 离线安装 IWYU(Include What You Use)
  • Linux库——库的制作和原理(1)_回顾动静态库、制作使用库
  • 【服务器与部署 26】配置管理实战:Ansible、Puppet自动化配置管理让运维效率提升10倍
  • 电磁兼容二:共模和差模问题
  • 【06】C#入门到精通——C# 多个 .cs文件项目 同一项目下添加多个 .cs文件
  • Spring Boot 整合 MyBatis 与 Druid 数据源全流程
  • 《整合Spring Cache:本地缓存、Redis与Caffeine对比实践》
  • 7.25总结
  • 详解Python标准库之内置函数
  • 20255年第四届创新杯(原钉钉杯)参考论文+标准答案发布
  • 融合与智能:AI 时代数据库的进化之路
  • Low DK(低介电常数)板材的好处:
  • Vue2上
  • 《Uniapp-Vue 3-TS 实战开发》自定义年月日时分秒picker组件
  • Linux之shell脚本篇(二)
  • 7.3.3 文件系统组件
  • 医疗影像领域中DICOM标准
  • 基于位移传感器的转子质心角度位置检测:原理分析与实现
  • 关于数据库表id自增问题
  • Springboot垃圾分类管理的设计与实现
  • 人工智能概述