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

Redis缓存异常问题深度解析:穿透、击穿与雪崩

最近正在复习Java八股,所以会将一些热门的八股问题,结合ai与自身理解写成博客便于记忆

一、缓存穿透

问题本质:访问不存在的数据,导致请求直接打到数据库

典型场景:

1. 恶意攻击:故意查询不存在的ID(如负值、超大数值)
2. 业务误操作:错误参数导致无效查询

危害表现:

数据库压力激增
可能引发数据库宕机

解决方案:

1. 空值缓存(推荐)

Object data = redis.get(key);
if(data == null) {data = db.query(...);if(data == null) {// 缓存空值并设置较短过期时间redis.setex(key, 300, "NULL"); } else {redis.setex(key, 3600, data);}
}

2. 布隆过滤器(高效判断存在性)

// 初始化过滤器
BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(), 1000000, 0.01);
// 写入时添加标记
filter.put("valid_key");// 查询前校验
if(!filter.mightContain(key)) {return null; // 直接拦截
}

3. 接口层校验(基础防御)

参数格式检查
范围校验(如ID必须>0)
频率限制

二、缓存击穿

问题本质:热点key过期瞬间,大量请求直接冲击数据库

典型场景

明星离婚等热点事件

秒杀商品详情页

重要系统配置项

危害表现:

数据库瞬时压力峰值
可能引发连锁故障

解决方案:

1. 互斥锁重建(推荐)

public Object getData(String key) {Object data = redis.get(key);if(data == null) {String lockKey = key + "_lock";if(redis.setnx(lockKey, "1")) { // 获取锁redis.expire(lockKey, 10);  // 防止死锁data = db.query(...);      // 查询数据库redis.setex(key, 3600, data);redis.del(lockKey);} else {// 未获取锁的请求休眠重试Thread.sleep(100);return getData(key);}}return data;
}

2. 逻辑过期时间(空间换时间)

// 存储带时间戳的数据
class RedisData {Object data;long expireTime;
}// 查询逻辑
RedisData redisData = redis.get(key);
if(redisData == null || System.currentTimeMillis() > redisData.expireTime) {// 异步更新缓存asyncUpdateCache(key); 
}
return redisData != null ? redisData.data : null;

3. 永不过期策略(配合后台更新)

设置key永久有效
后台定时任务定期更新缓存

三、缓存雪崩

问题本质:大量key同时过期,引发数据库连锁反应

典型场景:

1. 缓存服务重启
2. 相同TTL批量导入数据
3. 定时任务集中刷新缓存

危害表现:

数据库CPU/连接数被打满
统整体响应变慢或不可用

解决方案:

1. 差异化过期时间(根本解决)

// 基础过期时间 + 随机偏移量
int baseTime = 3600;
int randomTime = new Random().nextInt(600); // 0-10分钟随机
redis.setex(key, baseTime + randomTime, value);

2. 多级缓存架构(缓解冲击)

用户请求 -> CDN缓存 -> 分布式缓存 -> 本地缓存 -> DB
 

3. 熔断降级机制(保护数据库)

使用Hystrix等熔断工具

4. 缓存预热(启动防护)

// 系统启动时加载热点数据
@PostConstruct
public void initCache() {List<HotItem> hotItems = db.queryHotItems();hotItems.forEach(item -> redis.setex("item:"+item.id, 3600, item));
}

四、三大问题对比分析

问题类型触发条件  影响范围核心解决方案
穿透查询不存在数据单个恶意查询布隆过滤器、空值缓存
击穿热点key突然失效单个热点key互斥锁、逻辑过期
雪崩大量key同时失效整个缓存系统差异化过期、多级缓存

五、经典面试问题解析

1:布隆过滤器误判怎么办?

误判只会导致少量合法请求被拦截(假阳性),可通过以下方式优化:
1. 增加二进制数组大小
2. 优化哈希函数数量
3. 结合白名单机制

2:如何选择互斥锁的过期时间?

建议根据业务查询耗时动态设置:
1. 基础值 = 平均查询耗时 * 3
2. 不超过10秒(避免阻塞过久)
3. 必须设置过期防止死锁

3:多级缓存如何保证一致性?

采用分级失效策略:
1. 本地缓存TTL设置较短(如30秒)
2. 分布式缓存TTL较长(如10分钟)
3. 配合消息队列通知各节点失效

 

http://www.xdnf.cn/news/8861.html

相关文章:

  • 如何设计一个高性能的短链设计
  • ind_knn_ad环境搭建和运行【用自己的数据集】
  • 【Linux】系统程序−进度条
  • DAX权威指南3:变量、迭代函数与计算组
  • 【MySQL】第十一弹——JDBC编程
  • 如何用,向量表示3维空间种的有向线段(4,2,3)
  • 【电子通识】FPC连接器组成部分与不良案例术语
  • 常用正则表达式及语法详解
  • 【医学影像 AI】探索 MONAI:医学影像 AI 的综合框架
  • matlab实现SS-ELM和US-ELM
  • 计算机网络技术(二)
  • Linux多线程编程
  • 如何使用Webpack实现异步加载?
  • redis集群创建时手动指定主从关系的方法
  • 《技术择时,价值择股》速读笔记
  • 宽带卫星通信中的时分多址技术
  • STM32中的SPI通信协议
  • Vulkan 学习(15)---- Vulkan 完整渲染流程
  • 怎么判断文件是否支持多线程下载
  • 【Day36】
  • Python打卡训练营学习记录Day36
  • pyhton基础【4】判断
  • 使用Cursor生成需求文档+UI设计图
  • 【扫描线 线段树】P1856 [IOI 1998 ] [USACO5.5] 矩形周长Picture|普及+
  • firfox 国外版和国内版本账号不互通问题处理
  • 理论物理:为什么在极低温(接近绝对零度)时,经典理论失效?
  • 5.25 打卡
  • 高级特性实战:死信队列、延迟队列与优先级队列(三)
  • 《1.1_3_2 电路交换、报文交换、分组交换的性能分析|精讲篇》
  • git 把一个分支A的某一个 commit 应用到另一个分支B上