缓存问题总结
一、缓存穿透:*“查无此物”的攻击*
** **
**缓存穿透是指客户端请求的**数据在缓存中和数据库中都不存在**,这样缓存永远不会生效,*这些请求都会打到数据库*。
** **
1.1 原因分析
- 恶意请求:黑客暴力扫描不存在的ID(如-1、0等非法值)
- 逻辑缺陷:业务未校验参数有效性,直接透传至数据库
** **
1.2 解决方案
方案一:布隆过滤器(Bloom Filter)
原理:预加载所有可能存在的数据哈希值到布隆过滤器中,查询时先判断数据是否存在。
代码示例
1 | // 使用Guava实现布隆过滤器 |
****✅ 优点**:内存占用少(1百万数据仅需1MB)
*❌ 缺点*:存在误判率(可配置)
方案二:空值缓存
原理:将查询结果为空的键也存入缓存,设置较短过期时间(如5分钟)。
代码示例
1 | public String getProduct(Long id) { |
✅ 优点:实现简单
❌ 缺点:可能缓存大量无效Key
1.3 适用场景
- 电商商品ID扫描攻击
- 社交平台查询已注销用户
二、缓存雪崩:*“集体罢工”的灾难*
2.1 原因分析
- 批量过期:大量Key设置相同TTL,同时失效
- Redis宕机:集群故障导致所有请求压到数据库
2.2 解决方案
方案一:随机过期时间
1 | public void setProductCache(Long id, Product product) { |
✅ 优点:分散压力
❌ 缺点:无法应对Redis宕机
方案二:多级缓存架构
2.3 适用场景
- 双11整点秒杀
- 新闻APP热点事件推送
三、缓存击穿:*“顶流明星”的暴击*
3.1 原因分析
- 热点Key失效:高并发访问的Key突然过期
- 无保护机制:所有请求直接穿透到数据库
3.2 解决方案
方案一:分布式锁(Redisson实现)
原理:当缓存失效时,通过分布式锁控制仅一个线程重建缓存。
代码示例:
1 | public String getHotNews(String newsId) { |
✅ 优点:强一致性
❌ 缺点:性能损耗约10%
**
**
方案二:逻辑过期时间
原理:缓存永不过期,但存储数据时附加逻辑过期时间。
示例代码
1 | // 缓存数据包装类 |
✅ 优点:零等待时间
❌ 缺点:数据短暂不一致
3.3 适用场景
- 微博顶流明星发帖
- 小米手机秒杀活动
四、总结对比表
问题类型 | 触发条件 | 核心方案 | 性能影响 | 适用场景 |
---|---|---|---|---|
穿透 | 查询不存在数据 | 布隆过滤器 | 低 | 防恶意攻击 |
雪崩 | 批量Key失效/Redis宕机 | 随机TTL+多级缓存 | 中 | 大促活动 |
击穿 | 单个热点Key失效 | 分布式锁+逻辑过期 | 高 | 秒杀/顶流事件 |
综合应用
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Calico's Space!
评论