Redis命中率骤降是缓存穿透首个明确信号,表现为keyspace_hits/(keyspace_hits+keyspace_misses)断崖式下跌至40%以下且持续2分钟以上,此时大量请求的key既不在Redis也不在DB中,导致misses暴增、hits停滞,应优先检查INFO stats中keyspace_hits与keyspace_misses绝对值变化趋势。

Redis 命中率骤降是第一个明确信号
缓存穿透最直接的表征不是 DB 慢查询,而是 Redis 自身的命中率断崖式下跌。比如平时 keyspace_hits / (keyspace_hits + keyspace_misses) 在 90%+,突然掉到 40% 甚至更低,且持续 2 分钟以上,基本可以锁定为穿透——因为大量请求查的 key 根本没在 Redis 里,也不在 DB 里,所以既不命中、也不回填,misses 暴涨,hits 几乎停滞。
别等 DB 报警才反应:DB QPS 暴增、连接池打满、CPU 100%,往往已是穿透发生数分钟后的事。此时修复窗口极短,优先看 Redis 的 INFO stats 输出,重点关注 keyspace_hits 和 keyspace_misses 的绝对值变化趋势,而不是只盯百分比(避免低流量时段误判)。
监控空查询命中 DB 的日志模式
应用层必须埋点记录「缓存未命中 + DB 查询结果为空」的请求。这类请求本身不报错,但每一条都代表一次无效穿透。关键不是记录“查不到”,而是记录“查不到且没缓存空值”。
- 在缓存读取逻辑后、DB 查询前,加一行日志:
log.debug("cache-miss-and-db-empty", "key={}", key); - 用 ELK 或 Loki 聚合该日志,设置告警规则:5 分钟内出现 > 100 条相同前缀的
cache-miss-and-db-empty日志,立即触发企业微信/钉钉报警 - 注意过滤高频恶意 IP:如果同一
ip在 1 秒内发出 20+ 次不同 key 的空查询,直接走 WAF 封禁,不进应用层
用 redis-cli monitor 快速定位穿透 key 模式
线上紧急排查时,redis-cli -h 127.0.0.1 -p 6379 MONITOR 是最快手段。但别直接看全部输出——穿透请求通常有明显特征:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 大量
GET orders:user_后跟随机数字(如user_-1、user_999999999),且返回都是(nil) - 这些 key 在
redis-cli --bigkeys里完全不会出现,说明从未被写入过 - 配合
grep -E "GET orders:user_[0-9]+" | head -n 100快速抽样,确认是否集中在某类 key pattern
注意:MONITOR 会损耗性能,单次使用不超过 30 秒;生产环境建议改用 redis-exporter 暴露的 redis_cache_misses_total{key_pattern="orders:user_*"} 这类指标做长期监控。
布隆过滤器拦截失败要单独告警
如果已接入布隆过滤器(如 BloomFilter<long></long>),它的漏判率(false positive)可接受,但漏放(false negative)不可接受——即真实不存在的 key 被判定为“可能存在”,从而放过并打到 DB。这种情况必须监控:
- 在布隆过滤器校验后、DB 查询前,加判断:
if (!bloomFilter.mightContain(id) && db.queryById(id) == null),记录为bloom-filter-fail事件 - 该事件一旦每分钟超过 5 次,说明布隆过滤器容量或误差率设置不合理(比如预估数据量远小于实际,或
0.01误差率在超大数据集下失效) - 不要依赖布隆过滤器 100% 拦截:它只是第一道防线,后面仍需空值缓存兜底
真正难处理的不是技术方案,而是那些绕过布隆过滤器、又躲过参数校验的“合法但无意义”的请求——比如用户 ID 传了 0 或空字符串,数据库字段允许 NULL,但业务上绝不该存在。这类 case 必须靠业务语义校验卡死,不能只靠缓存层补漏。

















