缓存穿透风险等级取决于非法请求是否具备持续冲击数据库的能力,关键看数据库慢日志中无索引空查询、应用层空加载日志、db qps与错误率是否同步突增,而非仅看是否存在空值查询。

缓存穿透不是“有没有”,而是“打不打得垮”
缓存穿透风险等级不能靠“是否存在空值查询”来判断,关键看它是否具备持续冲击数据库的能力。一个 id=-1 的请求单次打库无害,但每秒 5000 次 id=9999999(超出业务 ID 范围)的请求,就可能直接耗尽 MySQL 连接池——尤其当 max_connections 被人为调低到 3 这类压测场景下,Too many connections 错误会在几秒内出现。
真正要盯住的三个信号
别只看 Redis 的 keyspace_misses,这些指标掩盖了穿透的真实杀伤力:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 数据库慢日志中是否集中出现
SELECT ... WHERE id = ?类无索引查询,且返回为空 - 应用层日志里是否高频出现类似
loadFromDBAndSetCache returned null for key: user:-1的记录 - 监控图表中 DB QPS 突增时段,与应用错误率(如 500、timeout)上升是否严格同步
布隆过滤器不是万能解药,得看落地成本
布隆过滤器能拦截大部分非法 key,但它本身有维护成本和误判率。用之前必须确认:
- 业务 key 是否可枚举或可预生成(比如用户 ID 是自增整数,范围已知;但订单号是 UUID 就很难建)
- 写入路径是否支持实时更新布隆位图(新增用户时,能否同步
bloomFilter.put("user:12345")) - 是否接受
false positive(误判存在)——这会导致少量真实请求被拦,但不会导致穿透;而false negative(漏判)才是致命的
空值缓存要带 TTL,且避免全量兜底
对确认不存在的 key 写入 SET user:-1 "" EX 60 是最简单有效的防线,但容易踩坑:
-
EX时间不能设太长(比如 24h),否则业务逻辑变更后,旧的“空”状态会长期污染缓存 - 不能对所有空结果都缓存,比如模糊搜索
search:keyword=abc*返回空,缓存它会掩盖后续真实数据的上线 - 注意区分“查无此 ID”和“查无此业务状态”,后者可能是临时不可用,不应缓存空值










