过期缓存:如何防止缓存被流量打穿?
防止过期缓存被流量打穿(缓存雪崩或缓存穿透)是缓存设计中的一个关键问题。以下是一些有效的方法来避免这些问题:
1. 设置不同的过期时间(过期抖动)
- 问题:如果大量缓存同时过期,可能导致瞬时高并发请求直接打到后端服务,造成压力激增。
-
解决方案:为不同缓存键设置一个随机范围内的过期时间(如
60s + rand(0,10s)
),使缓存失效时间分散,减少同一时间的大量请求同时触发缓存更新。
2. 缓存预热
- 问题:缓存过期后,第一次请求可能会因未命中缓存导致后端压力。
-
解决方案:
- 在缓存即将过期前,后台异步任务或定时任务预先加载并更新缓存。
- 例如,使用类似「双写缓存」策略,定期将新的数据更新到缓存中。
- 利用消息队列通知更新。
3. 请求锁或请求合并(Cache Stampede)
- 问题:大量并发请求同时访问同一缓存键时,会导致所有请求同时访问后端服务。
-
解决方案:
-
请求锁:当某个键的缓存过期时,使用分布式锁(如 Redis 的
SETNX
)控制只有一个请求去加载数据并更新缓存,其他请求等待或返回旧缓存。 - 请求合并:将多个并发请求合并为一个请求,减少对后端的压力。
-
请求锁:当某个键的缓存过期时,使用分布式锁(如 Redis 的
4. 永不过期缓存(逻辑过期)
- 问题:缓存失效可能造成瞬时流量打击后端。
-
解决方案:
- 缓存层设置为永不过期,但数据过期逻辑由应用层控制。
- 通过附加时间戳标记数据有效期,如果检测到逻辑过期,则后台异步更新缓存。
5. 限流与降级
- 问题:当缓存打穿导致后端服务承压时,可能进一步影响整体服务稳定性。
-
解决方案:
- 实施流量限流(如令牌桶算法)对突发流量进行限制。
- 实施降级策略(如返回默认值或备用数据),以减少对后端的压力。
6. 多级缓存
- 问题:单一缓存层无法有效应对高并发下的缓存击穿。
-
解决方案:
- 增加缓存层级,如本地缓存(如 Caffeine)+ 分布式缓存(如 Redis)。
- 本地缓存优先命中,减少对分布式缓存和后端的压力。
7. 布隆过滤器(防止缓存穿透)
- 问题:无效或非法请求不断击打缓存,导致所有请求直接到后端。
-
解决方案:
- 使用布隆过滤器快速判断请求是否存在合法性,拦截非法请求。
- 例如,判断缓存键是否可能存在,如果布隆过滤器判断不存在,则直接返回,避免访问后端服务。
8. 异步重建缓存
- 问题:同步重建缓存可能导致请求阻塞。
-
解决方案:
- 将缓存重建任务交由后台异步任务处理,用户请求返回旧数据或占位数据,待缓存完成更新后再提供新的数据。
热门日志
分类
- Django(4)
- ssdb(1)
- Mac(7)
- C(1)
- memcache(1)
- Python(32)
- Vim(8)
- sed(2)
- ansible(3)
- awk(4)
- shell(3)
- about(1)
- git(9)
- bat(4)
- svn(0)
- docker(1)
- Tornado(1)
- go(2)
- 架构(18)
- Vue(1)
- game(2)
- Html(6)
- Java(8)
- Mysql(37)
- Ajax(2)
- Jsp(1)
- Struts(8)
- Linux(72)
- JavaScript(39)
- Staruml(0)
- Mouth(1)
- Php(102)
- Windows(8)
- Message(48)
- Lua(10)
- Compute(1)
- Redis(7)
- Nginx(12)
- Jquery(1)
- Apache(1)
- cocos2d-x(8)