缓存穿透导致数据库CPU飙升而非Redis,因无效请求绕过缓存直击数据库;布隆过滤器通过位运算在微秒级拦截“肯定不存在”的请求,切断恶性循环。

缓存穿透直接导致数据库CPU飙升,不是Redis本身CPU高
很多人看到“Redis缓存穿透 → CPU 100%”,第一反应是Redis进程CPU爆了。错。真实链路是:大量无效请求绕过Redis(因为缓存里没有,也不会写空值),全部涌向数据库;数据库扛不住,连接池耗尽、慢查询堆积、锁等待加剧,最终表现为MySQL或PostgreSQL的CPU持续100%。Redis进程此时可能很闲,命中率甚至还在99%——它只是被“架空”了。
为什么数据库CPU会卡死在上下文切换和IO等待上
当穿透请求以高并发打进来,数据库要为每个请求做完整执行流程:解析SQL → 检查索引 → 执行查询 → 返回空结果 → 记录慢日志(如果开启)。哪怕只是查一个SELECT * FROM user WHERE id = -1,只要没走覆盖索引、没加前置校验,MySQL仍需打开表、定位B+树根节点、遍历到叶子页才发现无匹配行。这个过程消耗的是CPU时间片,而非纯IO。
更致命的是并发叠加效应:
- 每个连接占用独立线程(或协程),线程数快速逼近
max_connections上限 - 线程频繁阻塞在锁(如行锁/表锁)、磁盘IO(临时表、排序缓冲区溢出)上,触发内核级调度
- 操作系统被迫高频切换线程上下文,
sys时间占比飙升,us时间反而未必最高——但整体CPU利用率被推到100% - 连接池满后,应用层开始重试、超时、降级,进一步放大请求洪峰
布隆过滤器为什么能切断这个恶性循环
布隆过滤器不查数据库、不读Redis,只做位运算和哈希计算,整个判断过程在微秒级完成,且完全无锁、无IO、无上下文切换。它把“根本不存在”的请求拦在最外层,让数据库连被调用的机会都没有。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
关键点在于部署位置和更新机制:
- 必须部署在应用服务入口(如API网关、Spring Filter、Go middleware),不能放在Redis客户端内部
-
bf.add()必须与数据库写入强一致:新增一条有效user_id,必须同步写入布隆过滤器;删数据则无需删BF(允许误判) - 错误率设为
0.01时,100万key仅占约1.14MB内存,而避免的可能是每秒数千次无效查询 - 注意BF不支持删除,若业务有高频删ID场景,需配合
counting bloom filter或改用分段布隆+定时重建
空值缓存为什么救不了高并发穿透
setex("user:-1", 300, null)看似简单,但在高并发下极易失效:
- 第一个请求查库返回null,还没来得及写缓存,第二个请求已经进来,同样查库
- 若无互斥锁(如Redisson
RLock),多个线程会重复查库,形成“缓存击穿式穿透” - 空值缓存过期时间太短(如60秒),扛不住持续攻击;设太长(如24小时),又会导致真实数据上线后长期无法访问
- 空值本身占内存,恶意构造百万个不同非法ID,会迅速打爆Redis内存,引发
eviction和CPU抖动
真正可靠的方案永远是分层:布隆过滤器挡掉99.9%的非法ID,接口层做基础参数校验(如id > 0),最后才轮到空值缓存兜底。任何单点防御,在真实攻击面前都撑不过一分钟。

















