关键看数据是否有“临时性”分层:若所有缓存都带expire且需保护永久数据(如配置项),选volatile-lru;若大量key无过期时间,volatile-lru会退化为noeviction导致oom报错,此时应选allkeys-lru。

怎么判断该用 allkeys-lru 还是 volatile-lru
关键看你的数据有没有明确的“临时性”分层。如果所有缓存都带 EXPIRE,且你希望永久数据(比如配置项、白名单)绝对不被误删,那就必须用 volatile-lru;但如果大量 key 没设过期时间(比如用 SET 写入的会话 ID、计数器),volatile-lru 可能根本找不到可淘汰的键,最终退化成 noeviction —— 写操作开始报 OOM command not allowed when used memory > 'maxmemory' 错误。
实操建议:
- 用
INFO keyspace查看各数据库中带过期时间的 key 占比,低于 60% 就慎选volatile-*类策略 - 若业务中“临时缓存”和“长期元数据”混存,优先统一加
EXPIRE,再配volatile-lfu或volatile-ttl -
allkeys-lru对混合场景更鲁棒,但要注意:它可能把刚写入、还没来得及被访问的冷 key 当作“最近最少使用”误删
volatile-ttl 看似合理,为什么生产环境容易踩坑
volatile-ttl 的逻辑很直观:优先删快过期的。但它隐含一个强假设——所有带过期时间的 key,其 TTL 分布是均匀或递减的。现实中,很多系统会批量设置相同 TTL(比如全部 1 小时),导致大量 key 的 TTL 值几乎一样,Redis 随机采样后无法有效区分优先级,实际淘汰效果接近 volatile-random。
常见错误现象:
- 缓存命中率突然下降,日志里没看到明显过期事件,但
evicted_keys指标持续上涨 - 用
MEMORY USAGE发现大对象被频繁淘汰,而它们 TTL 其实还有 59 分钟
真正适合它的场景其实很窄:验证码、临时 Token、秒杀预热数据这类 TTL 差异极大、且天然有“先到先过期”语义的数据。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
allkeys-lfu 和 volatile-lfu 在高并发下表现差异在哪
LFU 策略依赖访问频次计数,而 Redis 的计数器不是原子递增,而是带衰减的近似值(避免旧访问长期影响决策)。这带来两个实际影响:
- 在突发流量下(比如某商品详情页被刷爆),
allkeys-lfu能更快识别出新热点,但衰减参数lfu-log-factor设得太小(默认 10),会导致计数器溢出变平,失去区分度 -
volatile-lfu因为作用域受限,当缓存中 LFU 值低的 key 很少时,淘汰可能停滞,触发写阻塞 - 两者都比 LRU 更吃 CPU:每次访问都要更新频率计数,QPS 超 5w 后可观察到
used_cpu_sys明显升高
调优建议:先用 CONFIG GET lfu-log-factor 查当前值,压测时对比 evicted_keys 和 keyspace_hits 曲线,若后者增长但前者不降,说明计数器已饱和,需调大 lfu-log-factor。
为什么 noeviction 不只是“默认策略”,而是关键安全兜底
很多人以为 noeviction 是懒人选项,其实它在两类场景里是硬性要求:一是 Redis 被当持久化存储用(比如作为消息队列的待处理任务表),二是主从复制链路中从库开启写权限(虽然不推荐)。这时候任何自动淘汰都等于数据丢失。
但要注意:noeviction 不代表完全安全。它只拦截写命令,不拦 INCR、HINCRBY 这类会增大内存的命令——这些仍会触发 OOM 报错。所以真正要保数据,得配合监控:
- 告警阈值不能只盯
used_memory_percent,得同时看mem_not_counted_for_evict(未计入淘汰统计的内存,比如客户端缓冲区) - 应用层捕获
OOM command not allowed错误后,必须降级到直连数据库,不能重试
最易被忽略的一点:Redis 重启后 maxmemory-policy 不会自动恢复为 noeviction,哪怕你没改过配置文件——因为 CONFIG SET 是运行时生效,重启即丢。必须在 redis.conf 里显式写死 maxmemory-policy noeviction 才算真正兜住。










