Redis 缓存穿透了,数据库挂了,彻底疯了
缓存没命中、数据库也没有,攻击者用不存在的热点 Key 直接把 DB 打崩。
事故现场:
// 常规缓存逻辑,看似没问题
public User getUser(Long id) {
String key = "user:" + id;
String json = redis.get(key);
if (json != null) {
return JSON.parseObject(json, User.class);
}
// 缓存未命中,查数据库
User user = userMapper.selectById(id); // 这里被击穿
if (user != null) {
redis.setex(key, 3600, JSON.toJSONString(user));
}
return user;
}
结果: 缓存形同虚设,所有请求打到 MySQL,连接池耗尽,服务 503。
解决方案演进
缓存空值
public User getUser(Long id) {
String key = "user:" + id;
String json = redis.get(key);
if (json != null) {
// 空字符串代表"数据库也没有"
return json.isEmpty() ? null : JSON.parseObject(json, User.class);
}
User user = userMapper.selectById(id);
if (user != null) {
redis.setex(key, 3600, JSON.toJSONString(user));
} else {
// 空值也缓存,但时间短一点
redis.setex(key, 60, ""); // 60 秒过期,防止攻击者长期占用
}
return user;
}

浙公网安备 33010602011771号