一、引言:为什么我们把缓存穿透称为“幽灵查询”
在分布式缓存体系里,Redis 常被置于最前端,像一道护城河,把 99% 的读流量挡在数据库之外。然而,护城河并非铜墙铁壁,当外部请求携带的 key 在缓存和数据库都不存在时,这道防线瞬间失效,所有压力倾泻到下游,我们称这种现象为“幽灵查询”。它之所以诡异,是因为:
-
查询目标“不存在”,让命中率监控失去意义;
-
请求量可大可小,完全取决于攻击者或异常客户端;
-
幽灵查询本身不破坏数据,却能让系统“自杀”。
本文将沿着缓存穿透的完整生命周期——诞生、扩散、突变、雪崩、恢复——剖析其机制,并给出可落地的治理哲学。
二、诞生:幽灵查询的三类根源
-
业务设计缺陷
典型场景是商品详情页:商品下架后,外部仍有旧链接或爬虫抓取。正常流程是下架时同步删除缓存,但如果删除动作失败,或删除后仍有延迟流量,缓存 miss 就会触发穿透。 -
恶意攻击
攻击者构造大量随机 key,或枚举不存在的 id,利用“不存在”这一事实绕过缓存。此类攻击往往伴随 HTTP 代理池、分布式节点,瞬时 QPS 可达数万。 -
系统级异常
配置漂移(如缓存前缀写错)、版本灰度(新旧 key 规则并存)、脏数据回灌(离线任务写错字段)都会制造大规模无效 key。
三、扩散:穿透流量的放大链
缓存穿透不是单点事件,而是一条链式反应:
-
Redis 返回 nil,应用线程继续访问数据库;
-
数据库返回空结果,应用再次透传给前端;
-
前端重试或并发访问,流量倍增;
-
数据库连接池被耗尽,其他正常查询被阻塞;
-
监控系统发现“Redis 命中率正常,数据库 CPU 100%”,误以为是慢 SQL。
这条链在秒级即可完成,给值班人员留下的反应窗口极短。
四、突变:从穿透到击穿、雪崩的临界点
很多工程师把“穿透、击穿、雪崩”混为一谈,其实三者有明确的演化路径:
-
穿透:大量不存在 key 直达数据库;
-
击穿:某个热点 key 过期,高并发同时回源;
-
雪崩:大面积 key 同时过期或 Redis 实例故障,导致全量回源。
幽灵查询最危险之处在于,它可以伪装成击穿或雪崩的导火索。当攻击者故意触发穿透,数据库已处于临界负载,此时任何一个热点 key 过期,都会成为压垮骆驼的最后一根稻草。
五、观测:如何量化幽灵查询
传统监控聚焦命中率、QPS、RT,却对穿透流量“视而不见”。推荐四组指标:
-
Nil Ratio:Redis 返回 nil 的次数 / 总查询次数,超过 5% 即需关注;
-
Miss-to-DB 延迟:缓存 miss 后访问数据库的耗时,可发现连接池排队;
-
Empty-Result 占比:数据库返回空结果的查询占比,高于 1% 即异常;
-
客户端重试率:同一 session 对同一 key 的重试次数,可识别恶意爬虫。
这四组指标需采集到秒级,并与业务事件(商品上下架、营销活动)做关联,才能还原幽灵查询的时空分布。
六、治理哲学:三层防线与两种心态
业界常用“布隆过滤器”、“空值缓存”、“接口限流”三板斧,但若只停留在技术层面,仍会陷入“打补丁”的困境。真正的治理需要三层防线:
-
语义层:让“不存在”变成“可预期”
商品下架时,不是简单删除缓存,而是写入一个“墓碑值”(逻辑删除标记),并设置短期 TTL。前端收到墓碑值即可直接 404,避免回源。 -
架构层:让“不存在”无法直达数据库
引入布隆过滤器或 Roaring Bitmap 过滤 99% 的幽灵 key;对剩余 1%,用本地 caffeine 缓存兜底,形成多级缓存。 -
运维层:让“不存在”可观测、可熔断
在 API 网关层增加“空结果限流”规则:同一 IP 或同一用户,对空结果 key 的访问频率超过阈值即触发熔断,返回 429 或验证码。
两种心态: -
灰度心态:任何新规则先在只读流量上灰度,确认 Nil Ratio 下降后再全量;
-
持续运营心态:每月复盘一次空结果 Top100 key,反推业务或数据问题,形成闭环。
七、案例复盘:一次 3 分钟的“幽灵风暴”
某电商平台大促前夕,凌晨 2:15 监控告警:数据库 CPU 飙至 95%,Redis 命中率却 98%。值班同学以为是慢 SQL,紧急 kill 掉几条查询后无果。后经日志分析发现:
-
攻击者利用商品 ID 递增特性,构造 40 万个不存在 id;
-
这些 id 全部穿透到数据库,空结果占比 7%;
-
数据库因大量“select … where id=?” 单点查询导致 CPU 抖动;
-
同时,正常用户刷新活动页,触发热点 key 过期,雪崩开始。
最终通过网关层临时拉黑攻击 IP,并一键开启“空结果缓存 60 秒”开关,3 分钟后恢复。复盘结论: -
事前未开启 Nil Ratio 监控;
-
墓碑值 TTL 设置过长(24h),导致下架商品仍被爬取;
-
API 网关缺少空结果限流策略。
八、未来演进:从“防御”到“免疫”
随着 Serverless 与边缘计算的普及,缓存层将下沉至 CDN 边缘节点。幽灵查询的治理也将从“中心拦截”转向“全网免疫”:
-
在边缘函数(Edge Function)内运行轻量级布隆过滤器,实现“最近一公里”拦截;
-
利用 WebAssembly 把商品下架事件实时同步到全球 200+ 节点,毫秒级扩散墓碑值;
-
用 eBPF 采集内核级 TCP 重传指标,提前识别分布式爬虫。
届时,缓存穿透不再是“黑天鹅”,而是一门可被量化、被编排、被免疫的确定性风险。
九、结语:穿透的终点是认知升级
Redis 缓存穿透表面是技术难题,本质却是“对不存在数据的认知缺失”。只有当我们把“不存在”纳入产品生命周期、把幽灵查询写进 SLA、把 Nil Ratio 刻进 KPI,才能真正让护城河固若金汤。