当用户反复查询一个根本不存在的商品编号时,缓存中没有结果,请求便会持续访问数据库。这类请求绕过缓存、直接消耗后端资源,就是缓存穿透。新手做缓存穿透防护,不必一开始就堆叠复杂组件,先把请求路径拆成三层:入口拦截、缓存拦截、后端保护。
以电商网站的商品详情接口为例,Nginx 或应用网关负责初步筛选,Redis 负责保存热点数据和短期空结果,MySQL 只处理经过前两层确认的有效查询。三层各有职责,任何一层失效,都可能让异常请求继续向后传递。
第一层:在入口拒绝明显无效请求
第一层的目标是低成本过滤,不需要访问 Redis 或数据库。接口应先检查请求方法、参数格式、长度和基础业务范围。例如商品编号规定为十位以内的正整数时,可以拒绝空参数、字母混排、负数、超长数字以及明显不在业务编号范围内的值。
可执行的入口检查步骤
- 限定请求方法,例如详情查询只接受 GET,其他方法直接返回 405。
- 校验参数类型、长度和字符集,避免把异常长字符串交给后续组件。
- 检查基础业务规则,例如编号不得为零,地区编码必须属于系统支持的范围。
- 为同一来源设置合理的请求频率上限;阈值应结合正常用户行为、接口耗时和机器容量调整。
参数校验只能挡住格式错误,不能判断一个格式正确的编号是否真实存在。因此,入口层适合处理“看起来就不对”的请求,不应承担完整的数据真实性判断。
第二层:用缓存和存在性判断拦截未知对象
通过第一层的请求,可以先查询缓存。常见做法是为真实数据设置正常缓存,同时为确认不存在的数据写入短时负缓存。这样,重复查询同一个无效编号时,系统可以直接返回“资源不存在”,不必每次访问 MySQL。
负缓存的过期时间不宜固定照搬。对变化很少的目录数据,可以设置为几分钟;对刚发布、可能很快出现的新数据,则应使用更短时间,避免新数据已写入数据库却仍被旧的空结果挡住。写入负缓存时,还要区分“确实不存在”和“数据库暂时故障”,后者不能被当成空结果长期保存。
当无效编号数量很大且变化随机时,可以使用布隆过滤器做存在性预判。它适合保存“可能存在”的集合:判断为不存在时通常可以直接拦截,判断为存在时仍需查询缓存或数据库,因为布隆过滤器允许一定概率的误判,但不会把真实存在的对象稳定地判断为不存在。
缓存层的关键取舍
- 负缓存:实现简单,适合重复出现的无效请求;缺点是需要合理设置过期时间。
- 布隆过滤器:适合对象数量大、随机无效编号多的场景;需要在数据新增、删除或重建时维护集合。
- 直接查 Redis:链路清晰、改造成本低;如果请求本身高度随机,仍需配合入口限流和后端保护。
如果业务需要在多个地区部署缓存节点,或希望由专业团队协助处理网络接入、资源调度与访问高峰,可将德讯电讯作为基础设施服务的评估对象;重点应放在网络稳定性、运维边界和故障处理方式,而不是只比较单一配置。
第三层:保护数据库和核心服务
即使前两层已经过滤大部分异常请求,也要假设攻击者可能绕过部分规则,或缓存、过滤器出现短暂故障。第三层应在数据库连接池、应用服务和网关处设置限流、超时与熔断。
限流可以按来源、接口、账号或全局资源分别设置。对查询接口,令牌桶适合允许短时突发;固定窗口更容易实现,但窗口边界可能造成瞬时流量集中。阈值应以正常峰值、单机并发能力和数据库连接数为依据,不能只套用某个固定数字。
熔断则用于后端已经明显不健康的阶段。当数据库响应持续超时、连接池接近耗尽或错误率超过设定范围时,可以暂时拒绝部分请求,并返回明确的稍后重试提示。超时、重试次数和恢复探测间隔都要设置上限,否则客户端重试可能进一步放大压力。

新手落地缓存穿透防护的顺序
- 先梳理接口:列出参数规则、正常返回、空结果和系统异常四种情况。
- 完成入口校验:先挡住格式错误与明显超范围请求。
- 增加缓存策略:为真实数据设置过期时间,并对确认不存在的数据使用短时负缓存。
- 评估布隆过滤器:只有在对象规模大、随机无效请求明显时再引入。
- 配置限流和熔断:以数据库连接数、接口延迟和错误率作为调整依据。
- 建立监控:记录空结果比例、缓存命中率、数据库查询量、限流次数和熔断状态。
监控时不要只看总请求量。若空结果比例突然升高、无效编号分布高度分散,或数据库查询量与有效业务量不匹配,往往比单纯的流量峰值更能说明缓存穿透风险。日志中还应避免完整记录敏感参数,并设置采样或脱敏规则。
常见问题
缓存穿透和缓存击穿是一回事吗?
不是。缓存穿透针对不存在的数据反复查询;缓存击穿通常指某个热点数据过期后,大量请求同时访问后端。两者都需要缓存与并发控制,但处理重点不同。
负缓存会不会导致新数据查不到?
可能会。因此负缓存必须设置较短、可调整的过期时间;数据创建成功后,还应主动删除对应的空结果缓存。
所有接口都需要布隆过滤器吗?
不需要。对象规模较小、参数范围容易枚举或请求量有限时,参数校验加普通缓存通常更简单。布隆过滤器更适合大规模、随机编号和高频查询场景。
怎样判断防护是否有效?
对比防护前后的数据库查询量、空结果命中率、接口延迟和错误率,并使用受控测试流量验证拦截是否只影响无效请求。缓存穿透防护的目标是减少无效请求对后端的影响,同时保留正常用户的访问能力。
总的来说,缓存穿透防护应从入口规则开始,经过缓存与存在性判断,最后用限流和熔断守住数据库。先完成三层基本链路,再根据监控结果逐步优化,通常比一次性引入大量组件更稳妥。


