redis中缓存穿透,及解决方案
Redis 缓存穿透是指客户端请求查询的数据,在 Redis 缓存和后端数据库中根本都不存在,导致每次请求都会绕过缓存,直接打到数据库上。
如果遭遇高并发请求或恶意攻击,数据库会因为承受不住这种无效查询的压力而崩溃。
🎯 缓存穿透发生的原因
缓存穿透的核心在于“查无此人”。通常由以下几种情况引发:
- 恶意攻击:黑客或爬虫故意构造大量数据库中没有的 ID(如负数 ID、随机生成的超长字符串等)发起请求,专门用来绕过缓存攻击数据库。
- 业务逻辑缺陷:前端或接口层没有做好参数校验,允许非法的参数(如格式错误的 ID)传入后端服务。
- 数据已删除:数据库中的某条数据被删除了,但缓存未同步清理。此时如果大量请求该数据,也会造成短暂的穿透。
💡 核心区别:
- 缓存穿透:查的是根本不存在的数据(缓存无,数据库也无)。
- 缓存击穿:查的是存在的热点数据(缓存无,数据库有,但刚好过期)。
- 缓存雪崩:大量数据在同一时间集体过期或 Redis 宕机。
🛠️ 缓存穿透的解决方案
解决缓存穿透的核心思路是:把无效请求拦截在数据库之前。以下是生产环境中常用的三道防线:
1. 接口层参数校验(第一道防线)
在请求刚进入系统时,就对关键参数进行合法性检查。
- 核心原理:过滤掉明显不合法的请求,连 Redis 和数据库都不用查。
- 执行方式:例如校验用户 ID 必须是正整数、字符串长度必须在合理范围内等。不符合规则的直接返回 400 错误。
- 优缺点:成本极低,能拦截大量低级恶意请求;但无法拦截那些“格式合法但实际不存在”的 ID。
2. 缓存空对象(核心兜底方案)
这是最简单且最常用的解决方案。
- 核心原理:即使数据库查不到数据,也把这个“空结果”缓存到 Redis 中,并设置一个较短的过期时间(如 2~5 分钟)。
- 执行流程:
- 请求查询 Redis 未命中。
- 查询数据库,发现数据也不存在。
- 将该 Key 在 Redis 中缓存为一个特殊空值(如
""、null或@@EMPTY@@)。 - 后续相同的请求会直接命中这个空值缓存,不再穿透到数据库。
- 优缺点:实现极其简单,能有效拦截重复的无效请求;但如果攻击者使用大量不重复的随机 ID 进行攻击,会在 Redis 中产生大量空值缓存,挤占宝贵的内存空间。
3. 布隆过滤器(终极拦截方案)
布隆过滤器是一种空间效率极高的概率型数据结构,通常作为缓存穿透的终极解决方案。
- 核心原理:在系统启动或数据加载时,将所有可能存在的有效数据 ID(如所有商品 ID、用户 ID)存入布隆过滤器。
- 执行流程:
- 请求到来时,先经过布隆过滤器判断。
- 如果布隆过滤器判定该 ID不存在,则该数据一定不存在,直接拦截请求。
- 如果判定可能存在,才放行去查询 Redis 和数据库。
- 优缺点:内存占用极小,查询速度极快,能从根本上挡住绝大多数无效请求;但它存在一定的误判率(即把不存在的数据误判为存在),且标准实现不支持删除操作,数据维护相对复杂。
