Redis「缓存穿透」是一个很经典的问题,本质是:请求的数据在缓存和数据库里都不存在,导致每次请求都会直接打到数据库。
一、什么是缓存穿透
场景:
- 用户请求一个 不存在的 key(比如 id = -1 或乱造的 id)
- Redis 查不到 → 去数据库查
- 数据库也查不到 → 返回空
- Redis 不缓存这个空结果
结果就是,每次请求都会重复打数据库
如果被恶意利用(比如刷不存在的 ID),数据库会被打爆。
二、常见解决方案
1.缓存空值(最简单有效)
做法:
- 数据库查不到 → 也写入 Redis
- 但存一个空值(比如
null或特殊标记) - 设置较短过期时间(如 60 秒)
| |
优点:
- 立刻生效
- 实现简单
缺点:
- 会占用少量缓存空间
2.使用布隆过滤器(Bloom Filter)(推荐)
在请求进入 Redis 前,先判断「这个 key 是否可能存在」
流程:
- 把所有合法 key(比如用户 ID)加入布隆过滤器
- 请求来了先判断:
- 不存在 → 直接返回(拦截)
- 可能存在 → 再查 Redis
特点:
| 特性 | 说明 |
|---|---|
| 不会漏判 | 一定不会把“存在的数据”判错 |
| 可能误判 | 可能把不存在的当存在 |
| 极省内存 | 非常适合大规模 key |
常见实现:
- RedisBloom 模块
- 本地布隆过滤器(Go 用
willf/bloom)
3.参数校验(第一道防线)
在接口层直接过滤非法请求
例如:
- ID < 0
- ID 超出范围
- 字符串不合法
| |
优点:
- 成本最低
- 最容易做
4.接口限流 / 风控
防止恶意攻击
常见方式:
- IP 限流(如 1 秒 100 次)
- 用户限流
- 网关限流(如 Nginx / API Gateway)
三、完整防穿透方案
「组合拳」:
| |
再加上:
- 空值缓存兜底
- 限流防攻击
四、总结
缓存穿透的本质:
查询不存在的数据,导致请求绕过缓存直击数据库
最优实践:
- 小项目:空值缓存 + 参数校验
- 大规模系统:布隆过滤器 + 空值缓存 + 限流