缓存失效主要由淘汰策略与过期时间叠加引发雪崩,而非淘汰策略单独导致;volatile类策略因漏设TTL、集中过期及采样误删热key风险极高,allkeys-lfu配合采样调优与过期抖动更稳定。

缓存失效不是淘汰策略直接导致的,而是策略+过期时间叠加触发的雪崩
Redis 本身不会因为启用了 allkeys-lfu 或 volatile-lru 就“主动让缓存失效”;真正出问题的,是淘汰策略在内存压力下批量误删热 key,或与集中过期形成共振。比如你用 volatile-lru,但凌晨 2 点批量写入的 10 万个商品缓存全设了 EXPIRE key 3600,一小时后整批过期——此时 Redis 内存刚好打满,volatile-lru 开始扫描淘汰,结果刚被访问过的热商品 key 被随机采样命中并删掉,数据库瞬间被打穿。
volatile-xxx 策略实际风险比想象中高
很多人选 volatile-lru 是图“只动带 TTL 的 key”,但漏设 TTL 的后果很隐蔽:
- 没加
EXPIRE的配置类 key、用户 session key(忘了设 ttl)会永久驻留内存,挤占空间 - 一旦内存触顶,Redis 自动 fallback 到
allkeys-lru或allkeys-lfu兜底,把本该保留的热数据也清掉 -
volatile-ttl更危险:它优先删“马上过期”的 key,等于加速雪崩节奏——本来还剩 30 秒的 key 被第一个删,反而让后续请求更早穿透到 DB
真实线上案例里,70% 的大面积失效都源于 volatile-* 策略 + 漏设 TTL + 固定过期时间三者叠加。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
allkeys-lfu 是当前最稳的默认选择
它不依赖是否设了 TTL,只按访问频次淘汰,天然保护高频 key,且对突发流量干扰小。但必须配合以下调整:
-
maxmemory-policy allkeys-lfu—— 明确启用 -
maxmemory-samples 10—— 默认是 5,采样太少易误判;调到 10 能显著降低冷热 key 识别偏差 - 禁用
volatile-ttl,哪怕业务真需要“快过期先删”,也改用应用层定时清理 + 延迟队列替代 - 所有
SET/SETEX操作必须带随机抖动:Java 用ThreadLocalRandom.current().nextInt(300),Python 用random.randint(0, 300),避免整点/整分集体失效
光改配置不够,得靠监控和拦截兜底
再好的策略也防不住代码里一句 DEL pattern* 或定时任务误执行 KEYS * + DEL:
- 开启慢日志:
slowlog-log-slower-than 10000,重点盯del、flushdb、eval - 定期查
INFO memory中的evicted_keys增速,突增说明淘汰已成常态,不是偶然事件 - SDK 层拦截高危命令:对
DEL、FLUSHALL做白名单校验,或改用SCAN+ 批量UNLINK
复杂点在于:淘汰不是独立事件,它永远和过期时间分布、写入节奏、采样随机性耦合在一起。一个没加抖动的 SETEX,可能三个月都没事,某天流量峰值+内存碎片一起到来,就直接崩盘。

















