缓存穿透直接导致数据库连接池耗尽,因其使大量无效请求绕过redis直击数据库,每个请求占用一个连接且难以释放,叠加空值未设ttl、布隆过滤器未全量初始化或参数校验缺失,迅速耗尽max_connections。

会,而且是直接原因。
缓存穿透为什么会导致数据库连接池耗尽
缓存穿透的本质是大量请求绕过 Redis,直击数据库——这些请求既不命中缓存,也不命中 DB,但每个请求仍会占用一个数据库连接。只要并发量够高、持续时间够长,连接池必然被打满。
-
max_connections是硬上限,比如 MySQL 默认 151,业务设为 500 也扛不住每秒几千个穿透请求 - 连接不会立刻释放:即使查询结果为空,事务未显式
COMMIT或连接未被主动CLOSE,连接就卡在“sleep”或“query”状态 - 连接泄漏风险放大:应用层若没做超时控制或异常兜底,空连接堆积更快
空值缓存没设 TTL 是常见死因
很多人写了 SET key "" 就以为防住了穿透,结果 Redis 内存缓慢上涨,而数据库连接数仍在飙升——因为没设过期,空值长期霸占缓存,但攻击者换一批新 key 继续打,老 key 不过期,新 key 又没缓存,照样穿透。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
SETEX key 30 ""(30 秒)是较稳妥的平衡点:足够挡掉扫描类请求,又不至于长期污染 - 绝对不要用
SET key ""或EXPIRE key 0这类等效永久存储 - PHP 中误写
$redis->set($key, '')而非$redis->setex($key, 30, ''),就是典型配置错误
布隆过滤器漏初始化 = 白加
布隆过滤器本身不查 DB、不读 Redis,性能极高,但前提是它得覆盖全量合法 key。如果只导入了 10 万用户,而实际有 800 万,那剩下 790 万的无效请求全都会穿透过去。
- 初始化必须走离线全量同步,不能靠线上增量补漏
- 即使
bf.exists('user_bf', '123456')返回True,DB 查不到也要走一遍SETEX user:123456 30 "",否则误判后下次仍穿透 - Python 的
pybloom-live或 Java 的guava BloomFilter都不自带持久化,需自行对接 Redis 或本地文件落地
真正拦住穿透,靠的是参数校验 + 空值缓存 + 布隆过滤器至少两项落地;单点防护,尤其是只扩容连接池,只会让问题更难定位、更晚暴露。










