php empty null 缓存穿透、缓存击穿、缓存雪崩
php empty null 缓存穿透、缓存击穿、缓存雪崩
一、缓存穿透(Cache )定义:
大量请求查询 根本不存在的数据(如恶意攻击或参数错误),导致每次请求都绕过缓存直接打到数据库,造成 DB 压力剧增甚至崩溃。
示例:
// 用户查询 ID = -1 的订单
Order order = cache.get("order:-1"); // null
if (order == null) {
order = db.queryById(-1); // DB 返回 null
// 若不缓存 null,下次同样请求仍会查 DB
}
应对方案:1.缓存空值(Null )
String key = "order:" + id;
Order order = redis.get(key);
if (order != null) {
return order; // 包括空值标记
}
order = db.getOrder(id);
if (order == null) {
redis.setex(key, 60, EMPTY_PLACEHOLDER); // 如 "NULL"
} else {
redis.setex(key, 3600, serialize(order));
}
️ 注意:需防止恶意构造海量不同无效 key 导致 Redis 内存爆炸(见下一点)。
2.布隆过滤器(Bloom )前置拦截
// 初始化时加载所有有效 ID 到 BloomFilter
BloomFilter validIds = BloomFilter.create(Funnels.longFunnel(), 1_000_000, 0.01);
// 查询时先判断
if (!validIds.mightContain(id)) {
throw new IllegalArgumentException("Invalid ID");
}
// 否则继续走缓存/DB 流程
优点:内存占用小,查询 O(1)
缺点:存在误判(false ),不能删除元素(可用 Bloom 改进)
3.接口层校验 + 限流二、缓存击穿(Cache )定义:
某个 热点 key 在缓存过期瞬间,大量并发请求同时发现缓存失效,全部打到 DBphp empty null,造成瞬时压力高峰。
与穿透不同:击穿是 真实存在的热点数据,只是缓存刚好失效。

应对方案:1.互斥锁(Mutex Lock)重建缓存
public Order getOrder(Long id) {
String key = "order:" + id;
Order order = redis.get(key);
if (order != null && !isEmptyPlaceholder(order)) {
return order;
}
// 尝试获取分布式锁(如 Redis SETNX)
String lockKey = "lock:order:" + id;
boolean locked = redis.setnx(lockKey, "1", 10); // 10s 过期防死锁
if (locked) {
try {
// Double Check:可能其他线程已加载
order = redis.get(key);
if (order == null || isEmptyPlaceholder(order)) {
order = db.getOrder(id);
if (order != null) {
redis.setex(key, 3600, serialize(order));
} else {
redis.setex(key, 60, EMPTY_PLACEHOLDER);
}
}
} finally {
redis.del(lockKey); // 释放锁
}
} else {
// 等待一小段时间后重试(或直接返回旧数据/降级)
Thread.sleep(50);
return getOrder(id); // 递归重试(注意次数限制)
}
return order;
}
优点:保证只有一个线程查 DB
缺点:增加延迟php empty nullphp empty null 缓存穿透、缓存击穿、缓存雪崩,高并发下可能大量线程阻塞
2.逻辑过期( ) + 后台刷新
{
"data": { ... },
"expireTime": 1712345678
}
此方案避免了锁竞争,但实现稍复杂。
3.热点 key 永不过期(慎用)三、缓存雪崩(Cache )定义:
大量 缓存 key 在同一时间失效(如 Redis 宕机重启、批量设置相同 TTL),导致所有请求瞬间打到 DB,引发 DB 雪崩。
应对方案:1.TTL 随机化()
int baseTTL = 3600; // 1小时
int jitter = new Random().nextInt(300); // ±5分钟
redis.setex(key, baseTTL + jitter, value);
简单有效,推荐默认使用。
2.高可用架构3.熔断 & 降级4.预热缓存四、综合防护策略(Java 工程师 )
问题
推荐方案
补充措施
缓存穿透
空值缓存 + 布隆过滤器
参数校验 + 接口限流
缓存击穿
互斥锁重建 / 逻辑过期

热点 key 永不过期(谨慎)
缓存雪崩
TTL 随机化 + Redis 高可用
多级缓存 + 熔断降级 + 预热
五、代码结构建议( Boot 示例)
@Service
public class OrderService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private OrderMapper orderMapper;
private static final String EMPTY = "NULL";
private static final int CACHE_TTL_BASE = 3600;
private static final int CACHE_TTL_JITTER = 300;
public Order getOrder(Long id) {
if (id == null || id <= 0) throw new IllegalArgumentException("Invalid ID");
String key = "order:" + id;
String cached = redisTemplate.opsForValue().get(key);
if (EMPTY.equals(cached)) {
return null; // 穿透防护
}
if (cached != null) {
return deserialize(cached);
}
// 尝试加锁重建
String lockKey = "lock:" + key;
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", Duration.ofSeconds(10));
if (Boolean.TRUE.equals(locked)) {
try {
// Double-check
cached = redisTemplate.opsForValue().get(key);
if (cached == null) {
Order order = orderMapper.selectById(id);
if (order != null) {
int ttl = CACHE_TTL_BASE + new Random().nextInt(CACHE_TTL_JITTER);
redisTemplate.opsForValue().set(key, serialize(order), Duration.ofSeconds(ttl));
return order;
} else {
redisTemplate.opsForValue().set(key, EMPTY, Duration.ofSeconds(60));
return null;
}
} else {
return deserialize(cached);
}
} finally {
redisTemplate.delete(lockKey);
}
} else {
// 短暂等待后重试(或降级)
try { Thread.sleep(20); } catch (InterruptedException e) {}
return getOrder(id); // 注意递归深度控制
}
}
}
总结
在 Cache-Aside 模式下,缓存穿透、击穿、雪崩 是必须系统性防御的问题。作为 Java 工程师php empty nullphp empty null 缓存穿透、缓存击穿、缓存雪崩,应:
通过组合策略,可在性能、一致性、可用性之间取得良好平衡。
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299
资源库 - 资源分享下载网 » php empty null 缓存穿透、缓存击穿、缓存雪崩
常见问题FAQ
- 关于资源售价和售后服务的说明?
- 代码有没有售后服务和技术支持?
- 有没有搭建服务?
- 链接地址失效了怎么办?
- 关于解压密码

