【Redis进阶篇|第一篇】如何解决缓存穿透问题

发布时间:2026/10/13 18:14:48
【Redis进阶篇|第一篇】如何解决缓存穿透问题 1. 什么是缓存穿透缓存穿透是指查询一个不存在的数据由于缓存中没有该数据那么我们的请求就只能绕过这个缓存去数据库中进行查找这样子就把缓存应该承担的压力全部打到了数据库上缓存该起到的作用也没有发挥出来这就叫做缓存穿透。在正常场景下缓存的工作流程是先查缓存命中则直接返回未命中则查询数据库并将结果写入缓存。但缓存穿透的特殊之处就在于查询的数据本身不存在因此缓存中永远不会有该数据每次请求都会落到数据库。我查询完之后根本就没有这个数据所以只能无功而返这样就导致我们的数据库直接暴露在外面假设突然有大量的请求突然发送过来比如说黑客的攻击等等那么此时数据库需要承担非常大的压力极易发生宕机的风险。如果这种请求量很大例如恶意攻击或爬虫大量请求不存在的 ID数据库会承受巨大的查询压力严重时可能导致数据库宕机。2. 缓存穿透的典型场景查询不存在的商品 ID用户或攻击者请求一个不存在的商品 ID缓存和数据库中都没有该记录。所以每次都只能在数据库中进行查询少量的请求数据库可以抵挡住但当大量数据同时打入数据库将会发生严重的安全问题。恶意攻击攻击者故意构造大量不存在的 key 发起请求绕过缓存直接打垮数据库。此时数据库就必定会被黑客整宕机。数据被删除某条数据在数据库中被删除但缓存中也没有对应记录后续查询全部穿透。3. 缓存穿透的解决方案3.1 缓存空值当查询不存在的时候我们可以知道既然不存在那代表这个东西就是没有那我们是不是就可以视为null呢所以我们可以在查询之后将null缓存到内存中这样在下一次查询的时候就不会直接查询数据库了同时为了防止不一致的问题发生我们可以给这个值加一个过期时间这样子就能很好的解决这个问题。缓存空值是我们在开发过程中很常用的一个方法简单并且高效的一个方法。// 伪代码示例缓存空值解决缓存穿透 public Object getData(String key) { // 1. 先查缓存 Object value redis.get(key); if (value ! null) { return value; } // 2. 缓存未命中查数据库 Object dbValue queryFromDB(key); if (dbValue null) { // 3. 数据库也不存在缓存空值并设置较短过期时间 redis.set(key, NULL, 300); // 5 分钟过期 return null; } // 4. 数据库存在写入缓存 redis.set(key, dbValue, 3600); return dbValue; }优点实现简单能有效拦截大量不存在的 key 请求。缺点会占用一定的缓存空间且空值过期后仍可能再次穿透。3.2 布隆过滤器布隆过滤器是一种概率型数据结构可以快速判断一个 key 是否可能存在。在请求到达缓存之前先用布隆过滤器去判断这个 key 是否存在如果布隆过滤器判断 key 不存在那就则直接返回不再查询缓存和数据库如果判断可能存在才继续走缓存和数据库查询。这样一来就能很好的过滤那些恶意的攻击将这些攻击挡在一堵墙外面。// 伪代码示例布隆过滤器解决缓存穿透 public Object getData(String key) { // 1. 先用布隆过滤器判断 key 是否存在 if (!bloomFilter.mightContain(key)) { // 2. 布隆过滤器判断不存在直接返回 return null; } // 3. 布隆过滤器判断可能存在继续查缓存 Object value redis.get(key); if (value ! null) { return value; } // 4. 缓存未命中查数据库 Object dbValue queryFromDB(key); if (dbValue ! null) { redis.set(key, dbValue, 3600); } return dbValue; }优点内存占用小、查询效率高能拦截绝大多数不存在的 key。缺点存在一定的误判率可能把不存在的 key 误判为存在且需要提前把所有合法 key 加载到布隆过滤器中。3.3 接口层校验在接口入口处对请求参数进行合法性校验提前拦截明显不合法的请求。例如ID 必须为正整数、ID 必须在合理范围内、参数格式必须正确等。通过参数校验可以过滤掉大量恶意构造的无效请求。这是一个初步的方法只能过滤掉一些简单的攻击但黑客的恶意攻击并不会这么简单因此我们可以对这个方案进行一个升级上一个方案是用了一个过滤器来实现那么我们可以想一想既然这两个都可以过滤那么为什么不首先用接口层校验进行第一次初筛布隆过滤器进行第二次细筛呢就好比我们进行过滤一样这样的效果会更好一些。// 伪代码示例接口层参数校验 public Object getData(String id) { // 1. 参数合法性校验 if (id null || !id.matches(\\d)) { return null; // 非法参数直接返回 } // 2. 继续走缓存和数据库查询 // ... }3.4 限流与降级对于无法完全避免的穿透请求可以通过限流和降级策略保护数据库。例如对数据库查询接口做限流超过阈值时直接返回默认值或错误提示或者对数据库进行降级处理避免数据库被压垮。这是最后的一个办法当前面的方法已经无法抵挡住这些恶意的攻击之后我们只能采取最后的这个方案进行最后的拦截。4. 方案对比与选型建议方案实现难度拦截效果适用场景缓存空值低较好数据量不大、key 数量有限的场景布隆过滤器中很好key 数量大、需要高效拦截的场景接口层校验低一般作为前置拦截手段配合其他方案使用限流与降级中兜底保护高并发场景下的最后一道防线在实际项目中通常建议组合使用先用接口层校验拦截明显非法的请求再用布隆过滤器拦截不存在的 key最后用缓存空值兜底同时配合限流降级保护数据库。5. 总结缓存穿透的本质是查询不存在的数据导致缓存失效核心解决思路是让不存在的 key 也能被缓存拦截或者提前判断 key 是否存在。推荐采用「接口校验 布隆过滤器 缓存空值」的组合方案并根据业务场景辅以限流降级从而有效保护数据库提升系统稳定性。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询