缓存穿透、缓存雪崩以及缓存击穿

本文深入探讨了缓存系统中常见的三大问题:缓存穿透、缓存雪崩和缓存击穿,分析了这些问题产生的原因及对数据库带来的压力,并提出了有效的解决方案,包括设置空值、使用布隆过滤器、随机设置key的过期时间和将热点数据设为永久有效。

1. 缓存穿透

1.2 问题简述

缓存击穿就是用户请求数据在数据库对应查询结果为空时,对该结果不进行缓存,从而导致每次查询为空都会直接访问数据库

1.2 解决方法
  1. 设置空值

    将在数据库查询为 nullkey 也缓存起来,设置一定的过期时间,这样只会在 key 失效的额时候访问数据库,可以减轻数据库压力

  2. 使用布隆过滤器

2. 缓存雪崩

2.2 问题简述

在同一时间内,大量 key 失效,导致对这些 key 的访问都落在数据库上,造成数据库的庞大压力

2.2 解决方法

随机 设置 key过期时间,使得 key 失效时间均匀分布,从而分散数据库压力

3. 缓存击穿

3.2 问题简述

频繁访问的热点数据失效,导致一时间大量的热点数据访问落在数据库上,可能导致数据库崩溃

3.2 解决方法

频繁访问的热点数据可以设置为永久不失效


后续更新java+redis+springboot实现代码

<think>嗯,用户想深入理解缓存击穿穿透雪崩的区别及解决方案。从对话历史看,我之前已经给过详细对比表格和解决方案,但用户可能希望更直观的总结。 用户提供的引用内容很全面,特别是引用[4]的对比表格非常清晰。需要突出三个问题的核心差异点: 1. 穿透是查存在的数据(恶意请求) 2. 击穿是热点key失效(突发流量) 3. 雪崩是大面积key同时失效(系统风险) 注意到用户特别标注要"区别+解决方案"并列呈现,所以考虑设计双栏结构:左栏特征描述,右栏对应解决方案。这样对比更鲜明。 关于解决方案的优先级: - 穿透首选布隆过滤器(引用[1][4]都强调) - 击穿重点在锁机制和逻辑过期(引用[3]示例代码很实用) - 雪崩需要TTL随机化+多级缓存(引用[2][5]都提到) 用户可能对实际场景更关注,准备补充电商案例: 1. 穿透:黑客用负数ID刷接口 2. 击穿:iPhone新品开售时缓存失效 3. 雪崩:整点秒杀活动缓存集中过期 最后要强调引用[5]的实践建议:监控命中率比事后补救更重要。考虑在总结部分加入这个观点。</think>以下是缓存击穿缓存穿透缓存雪崩的核心区别及解决方案的对比总结: --- ### **一、核心区别对比** | **问题类型** | **触发条件** | **本质原因** | **典型场景** | **影响范围** | |----------------|---------------------------------------|-------------------------------|-------------------------------|-----------------------| | **缓存穿透** | 查询**存在的数据**(数据库也无记录) | 恶意攻击或业务异常[^4] | 频繁请求非法ID(如`user_id=-1`) | 持续冲击数据库 | | **缓存击穿** | **热点Key过期瞬间**遭遇高并发请求 | 单点失效引发雪崩效应[^3] | 热搜商品/秒杀活动Key过期 | 数据库瞬时压力剧增 | | **缓存雪崩** | **大量Key同时过期** | 缓存集中失效[^2] | 促销活动结束大批商品缓存失效 | 数据库被压垮甚至宕机 | > **关键公式**: > - 缓存雪崩风险:$$ Risk = \frac{N_{expired}}{N_{total}} \times QPS $$ > ($N_{expired}$:同时过期Key数量,$QPS$:请求量) --- ### **二、针对性解决方案** #### **1. 缓存穿透解决方案** - **布隆过滤器 (Bloom Filter)** - 前置位数组存储所有合法Key的哈希值,拦截非法请求[^4] - 内存优化:1亿Key仅需约120MB - 误判率公式:$$ P \approx \left(1 - e^{-\frac{k \cdot n}{m}}\right)^k $$ ($k$:哈希函数数量,$n$:元素数量,$m$:位数组大小) - **缓存空值 (Null Caching)** ```java // 伪代码示例 Object data = cache.get(key); if (data == null) { data = db.query(key); if (data == null) { cache.set(key, "NULL", 300); // 缓存空值300秒 } } ``` - 对空结果设置短时缓存(需定期清理)[^3] #### **2. 缓存击穿解决方案** - **互斥锁 (Mutex Lock)** ```python # Redis分布式锁伪代码 if not cache.exists(key): if redis.setnx("lock:"+key, 1, ex=10): # 获取锁 data = db.query(key) cache.set(key, data, ttl=60+randint(0,30)) # 回填缓存并随机TTL redis.delete("lock:"+key) else: time.sleep(0.05) # 等待50ms后重试 return cache.get(key) ``` - 仅允许一个线程重建缓存[^1] - **逻辑过期时间** - 缓存Value结构:`{"data": "真实数据", "expire": 1717020800}` - 异步更新:线程发现过期时触发更新,直接返回旧数据 #### **3. 缓存雪崩解决方案** - **TTL随机化** $$ TTL_{new} = TTL_{base} + random(0, 300) $$ 避免批量Key同时过期[^2] - **多级缓存架构** ```mermaid graph LR A[客户端] --> B[本地缓存 Caffeine] B --> C{命中?} C -->|是| D[返回数据] C -->|否| E[Redis集群] E --> F{命中?} F -->|是| D F -->|否| G[数据库] G --> H[回填各级缓存] ``` - 本地缓存 → Redis → 数据库 三级拦截[^5] - **熔断降级** 监控数据库QPS,超过阈值时启动限流(如Sentinel) --- ### **三、通用防御策略** | **策略** | 穿透 | 击穿 | 雪崩 | 实现复杂度 | |------------------|------|------|------|------------| | 布隆过滤器 | ✅✅✅ | ❌ | ❌ | 中 | | 互斥锁 | ❌ | ✅✅✅ | △ | 高 | | 缓存空值 | ✅✅ | ❌ | ❌ | 低 | | TTL随机化 | ❌ | △ | ✅✅✅ | 低 | | 多级缓存 | ✅ | ✅✅ | ✅✅ | 高 | | 热点Key永过期 | ❌ | ✅✅ | ❌ | 中 | > **设计原则**: > - 穿透:**过滤非法请求**(布隆过滤器为核心) > - 击穿:**保障热点数据高可用**(锁+逻辑过期) > - 雪崩:**分散失效风险**(TTL随机化+多级缓存)[^4][^5] --- ### **四、典型场景案例** 1. **缓存穿透** - **场景**:黑客用脚本遍历用户ID(包括负数) - **方案**:布隆过滤器拦截非法ID请求[^1] 2. **缓存击穿** - **场景**:双11零点热门商品缓存失效 - **方案**:Redis分布式锁控制单线程回填缓存[^3] 3. **缓存雪崩** - **场景**:整点秒杀活动缓存集中过期 - **方案**:基础TTL=1小时 + 随机300秒偏移量[^2] --- ### **总结** | **问题** | **核心矛盾** | **必选方案** | |----------------|-----------------------|----------------------------| | 缓存穿透 | 非法请求穿透防线 | 布隆过滤器 + 空值缓存 | | 缓存击穿 | 单点失效引发雪崩 | 互斥锁 + 逻辑过期 | | 缓存雪崩 | 批量失效压垮数据库 | TTL随机化 + 多级缓存架构 | > 实践中需结合**监控告警**(缓存命中率、DB QPS)和**熔断降级**机制[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值