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;

}

posted @ 2026-03-14 15:05  去年冬天见了一面  阅读(0)  评论(0)    收藏  举报