缓存穿透是指查询数据库和缓存中均不存在的数据,导致请求持续穿透缓存直击数据库,引发数据库压力剧增甚至宕机;典型表现为redis命中率骤降、大量null响应集中于非法key(如负id、超长随机数),并伴随qps暴涨但业务转化率趋零。

缓存命中率骤降是穿透最直接的信号
缓存穿透发生时,redis.get() 返回 null 的频率会远高于正常业务波动。这不是偶发 miss,而是持续、批量的 miss —— 比如 1 分钟内 get 调用 10 万次,其中 9 万次返回 null,命中率跌到 10%,基本可以判定存在穿透行为。
关键不是看绝对 miss 数,而是看 null 响应的分布特征:
- 大量请求集中在相似 pattern 的 key 上(如
user:-1、order:999999999) - 这些 key 在数据库层也查不到记录,且无业务合理性(负 ID、超长随机数、格式非法)
- 对应接口 QPS 暴涨,但实际业务转化率趋近于 0
用 Redis 自带命令快速定位异常 key
不要等监控告警才动手,出问题时第一时间用 redis-cli 抓现场:
- 执行
redis-cli --scan --pattern "user:*" | head -n 1000 | xargs -I{} redis-cli get {} | grep -c "^$"快速统计某前缀下空值比例 - 用
redis-cli --bigkeys查是否有大量小 value 的 key(穿透常伴随海量无效 key 占用内存) - 开启慢日志并过滤
get命令:CONFIG SET slowlog-log-slower-than 0,再查SLOWLOG GET 100,观察是否出现大量get耗时突增(说明后端 DB 已开始卡顿)
在应用层埋点比依赖 Redis 监控更准
Redis 自带的 INFO keyspace 只能告诉你某个 db 的 keys 总数和 expires 数,无法区分“合理 miss”和“恶意穿透”。真正有效的监控必须下沉到业务代码:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- 在缓存查询逻辑后加统一拦截:每次
redis.get(key)返回null,记录key、timestamp、traceId到独立日志文件或 Kafka topic - 对日志流做实时聚合:每 10 秒统计
key的前缀频次(如提取user:(-?\d+)中的数字部分),发现负数、超大整数集中出现就触发告警 - 避免只监控“空值数量”,要关联下游 DB 查询耗时——如果
redis.get()为空后,db.query()平均耗时 > 200ms 且失败率 > 95%,基本确认穿透已影响 DB
布隆过滤器的 false positive 会干扰监控判断
如果你用了布隆过滤器做前置拦截,注意它本身会产生误判。当 bloomFilter.mightContain(key) 返回 true,但实际 DB 查不到,这类请求仍会走到缓存写入逻辑,造成“伪穿透”日志噪音。
正确做法是把布隆过滤器的判断结果也打点:
-
bloomFilter.mightContain(key) == false→ 直接拒掉,不记缓存 miss,也不查 DB -
bloomFilter.mightContain(key) == true但redis.get() == null且db.query() == null→ 这才是真实穿透,需单独标记为penetration_confirmed - 定期用线上真实 key 集合校准布隆过滤器的
expectedInsertions和fpp参数,避免误判率长期偏高掩盖真实攻击
穿透监控真正的难点不在采集,而在区分“业务脏数据”和“攻击流量”。一个没做参数校验的手机号查询接口,和黑产扫号脚本,在 Redis 层看起来完全一样。必须结合上游来源(IP、User-Agent)、请求频率、key 构造规律才能下结论。










