Redis 缓存问题:穿透、击穿、雪崩、Big Key
在高并发系统里,Redis 经常被放在数据库前面,当作一层缓存。
正常情况下,请求流程是这样的:

这样做的好处很明显:Redis 快,可以帮 MySQL 分担大量压力。
但是缓存不是万能的,用不好也会出问题。常见的 Redis 缓存问题主要有:
1. 缓存穿透 2. 缓存击穿 3. 缓存雪崩 4. Big Key
一、缓存穿透
1. 什么是缓存穿透?
缓存穿透指的是:
查询的数据在 Redis 中不存在,在数据库中也不存在,导致每次请求都会打到数据库。
比如用户请求:
/product/999999
但是商品 999999 根本不存在。
流程就变成:

那么这些请求都会绕过 Redis,直接打到数据库。
解决方案:
1.参数校验
2.缓存空对象
3.布隆过滤器(布隆过滤器适合数据量大、非法请求多的场景。)
二、缓存击穿
缓存击穿指的是:某一个热点 key 突然失效,大量请求同时打到数据库。
注意重点是:一个热点 key。
比如一个爆款商品:

这个商品访问量非常高,平时大家都从 Redis 查。
但是某一刻,这个 key 刚好过期了。
这时候大量请求同时进来:

流程就变成

解决方案:
1. 互斥锁:缓存失效后,只允许一个线程去查数据库并重建缓存,其他线程等待。

示例代码:
public Product getProductById(Long id) {
String key = "product:" + id;
String lockKey = "lock:product:" + id;
String json = redisTemplate.opsForValue().get(key);
if (json != null && !"NULL".equals(json)) {
return JSON.parseObject(json, Product.class);
}
Boolean lock = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(lock)) {
try {
// 双重检查,防止其他线程已经重建缓存
json = redisTemplate.opsForValue().get(key);
if (json != null && !"NULL".equals(json)) {
return JSON.parseObject(json, Product.class);
}
Product product = productMapper.selectById(id);
if (product == null) {
redisTemplate.opsForValue().set(key, "NULL", 2, TimeUnit.MINUTES);
return null;
}
redisTemplate.opsForValue().set(
key,
JSON.toJSONString(product),
30,
TimeUnit.MINUTES
);
return product;
} finally {
redisTemplate.delete(lockKey);
}
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
String retryJson = redisTemplate.opsForValue().get(key);
if (retryJson != null && !"NULL".equals(retryJson)) {
return JSON.parseObject(retryJson, Product.class);
}
return null;
}
这里的锁本质上就是 Redis 的:
SET lock:product:1001 1 NX EX 10
这样可以避免程序宕机后锁一直不释放。
2.热点key不过期(每次查询重置超时时间)。
三、缓存雪崩
1.什么是缓存雪崩?
缓存雪崩指的是:
大量缓存 key 在同一时间失效,或者 Redis 整体宕机,导致大量请求瞬间打到数据库。
比如我们批量缓存了 10 万个商品,并且统一设置 30 分钟过期:
![]()
如果这些 key 是同一时间写入的,那它们很可能同一时间过期。
30 分钟后:

解决方案:
1. 过期时间加随机值


2.缓存预热:系统启动或者活动开始前,提前把热点数据加载到 Redis。
四、Big Key 问题
Big Key 不是说 key 的名字很长,而是说:
某个 key 对应的 value 太大,或者集合类型中元素太多。
比如:

这些都可能是 Big Key。
2. Big Key 的危害
Redis 核心命令执行主要是单线程。
如果对 Big Key 执行:

redis 会一次性处理大量数据,其他请求只能排队。
结果就是:Redis 卡顿、接口变慢、请求超时、CPU 飙高。
3.如何发现 Big Key?
使用 redis-cli --bigkeys
![]()
这个命令可以扫描出各类型中比较大的 key。生产环境建议低峰期执行。
总结:
穿透是查不存在的数据,击穿是一个热点 key 失效,雪崩是一大片 key 同时失效,Big Key 是一个 key 太胖,热点 Key 是一个 key 太火。
更多推荐




所有评论(0)