缓存穿透本质是无效key击穿缓存直击db,需区分非法key与合法空数据;空值缓存须用标记对象+明确ttl(2~5分钟);布隆过滤器用于前置拦截高频非法请求;应结合参数校验、布隆过滤、空值缓存三层防御。

缓存穿透的本质是“无效key打穿缓存直击DB”
不是所有空查询都该进缓存,关键要区分“业务上合法但暂无数据”和“根本不可能存在的非法key”。比如 user_id=9999999999(超长ID)、id=-1、id=abc 这类请求,数据库必然查不到,也不该让它们反复走DB。真正需要保护的,是那些“业务逻辑允许存在、但当前为空”的场景,比如刚注册还没填资料的新用户。
空值缓存必须带过期时间且不能用 raw null
直接往 Redis 存 null 或空字符串会带来两个问题:一是反序列化时无法区分“缓存里真存了 null”和“根本没命中缓存”;二是如果忘了设过期,这些空 key 会长期占内存。所以实际操作中:
- 用自定义标记对象(如 Java 的
NullValue类)或特殊字符串(如"__NULL__")代替原始null - 空值过期时间必须明确设置,推荐
2~5 分钟,太短起不到拦截效果,太长浪费内存 - 读取时先判断是否为标记值,是则直接返回
null,不是再走正常逻辑
布隆过滤器适合高吞吐非法请求拦截场景
当系统面临大量随机非法 key 攻击(比如爬虫扫 ID、恶意构造参数),光靠空值缓存会把 Redis 塞满无效 key。这时布隆过滤器更合适——它在请求到达缓存前就做一次轻量级校验:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 预热阶段把所有合法
user_id、product_id等主键写入布隆过滤器(可用 Redis 的bf.add或本地ScalableBloomFilter) - 请求来时先查布隆过滤器,
bf.contains(id) == false就直接拒绝,不碰 Redis 也不查 DB - 注意布隆过滤器有误判率(
true不一定真存在,但false一定不存在),所以它只能做前置拦截,不能替代空值缓存
单一方案不够,得组合使用才稳
真实系统里没人只靠一种手段防穿透。最常见的是三层防御:
- 第一层:接口参数校验(如
id > 0、正则匹配手机号格式),筛掉明显非法输入 - 第二层:布隆过滤器拦截高频随机攻击,减轻 Redis 和 DB 压力
- 第三层:空值缓存兜底,覆盖校验通过但 DB 确实无数据的合法请求
漏掉任何一层,都可能在某个流量峰值点被击穿。尤其是布隆过滤器重建时机和空值 TTL 的配合,容易被忽略——比如批量导入新数据后没同步更新布隆过滤器,会导致大量合法请求被误拒。










