内存淘汰策略本身不能减少缓存穿透风险,选错策略反而会加剧问题;缓存穿透是请求查不到数据(缓存和DB均无),而淘汰策略仅作用于已存在的key,对根本不存在的key无效,二者作用域完全不同。

直接说结论:内存淘汰策略本身不能减少缓存穿透风险,选错策略反而会加剧问题。 缓存穿透是请求查不到数据(缓存和 DB 都没有),而淘汰策略只管“已有数据该删谁”,两者作用域完全不同。强行用 volatile-ttl 或 allkeys-lru 去“防穿透”,属于误用。
为什么淘汰策略对缓存穿透无效?
缓存穿透的本质是「空查询放大」——比如恶意构造大量不存在的 user_id=999999999 请求,这些 key 本来就没存过,自然不会被任何淘汰策略处理。Redis 根本没机会“淘汰”它们,因为它们压根不在内存里。
常见误解是:以为设置 volatile-ttl 让 key 快过期,就能“提前清掉潜在穿透请求”。但问题在于:没存过的 key 就没有 TTL,也不会被纳入淘汰候选集。
- 淘汰策略只作用于已存在的 key
- 穿透请求对应的 key 在 Redis 中根本不存在(
EXISTS返回 0) -
TTL命令对不存在的 key 返回-2,不是-1
哪些淘汰策略可能让穿透更难察觉?
某些策略会让空查询行为更隐蔽,间接拖慢问题暴露速度:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
-
noeviction:写失败会立刻报错(error) OOM command not allowed when used memory > 'maxmemory',容易发现容量瓶颈,但不解决穿透 -
volatile-lru或volatile-ttl:如果误把空结果缓存成NULL并设了过期时间,这些NULL值会被纳入淘汰范围,导致后续真实请求命中空缓存,掩盖了穿透源头 -
allkeys-random:随机淘汰可能踢掉有效缓存,增加 DB 查询概率,放大穿透影响
注意:NULL 缓存必须显式写入(如 SET user:999999999 "null" EX 60),Redis 不会自动存空值。
真正该做的三件事(和淘汰策略无关)
防穿透要绕开淘汰机制,从请求入口和数据存在性判断入手:
- 用布隆过滤器(Bloom Filter)前置拦截:初始化时把所有合法
user_id加入 Redis 的Bloom结构,请求先BF.EXISTS,返回 0 就直接拒绝 - 缓存空对象时明确控制生命周期:写
SET user:999999999 "" EX 300,避免用EXPIRE单独设 TTL,防止因淘汰策略误删后又反复穿透 - 监控
keyspace_hits和keyspace_misses指标:如果keyspace_misses突增且对应 key pattern 高度离散(如user:*9999*),基本就是穿透信号
淘汰策略只负责“有数据时怎么删”,穿透防御得靠“没数据时怎么拦”。别指望 maxmemory-policy 解决它,那是给错对象递刀子。

















