想要准确判断是否发生了 Redis 内存淘汰行为,首先要通过 INFO stats 中的 evicted_keys 是否呈脉冲式增长、expired_keys 是否同步快速上升,以及 total_commands_processed 是否出现下滑这三个核心指标进行交叉验证。只有结合这几项数据一起分析,才能更有效地定位 Redis 性能抖动是否由内存淘汰策略引发。如果 evicted_keys 始终为 0,但延迟依然很高,那么问题通常不在淘汰策略本身,更可能与 AOF rewrite、RDB fork,或 LFU 计数器衰减重分配等机制有关。

怎么确认抖动真由淘汰策略触发
当发现 Redis 延迟明显升高时,不要第一时间认定是内存淘汰策略导致的,建议先查看 INFO stats 中是否确实存在淘汰行为。重点观察三个字段:evicted_keys 是否出现脉冲式上涨(例如每秒骤增上千)、expired_keys 是否同步飙升,以及 total_commands_processed 是否显著下降。只有当这三项指标同时出现异常时,才能说明 Redis 淘汰操作正在抢占主线程资源,从而引发性能抖动和延迟波动。
如果 evicted_keys 持续为 0,但延迟尖峰依旧存在,那么问题大概率并非 Redis 淘汰策略本身,而是出在 AOF rewrite、RDB fork,或者 LFU 计数器衰减重分配等后台机制上。
volatile-ttl 在短生命周期 key 场景下为什么容易抖动
volatile-ttl 会每 100ms 扫描一次 expires 字典。当大量 key 的剩余 TTL 都接近 0 时,比如批量设置了 60s、120s 这类整秒过期时间,就很容易集中触发惰性检查与主动驱逐。这个过程会占用 Redis 主线程,进而导致以下典型现象:
redis-cli --latency出现周期性的 20–50ms 延迟尖峰- 客户端偶发
READONLY You can't write against a read only replica报错(本质上往往是写命令被阻塞) INFO memory中的mem_fragmentation_ratio波动明显增大(频繁进行内存分配和释放)
allkeys-lfu 替代 volatile-ttl 的实操要点
将 Redis 淘汰策略从 volatile-ttl 切换到 allkeys-lfu,并不是简单修改一行配置就能完成,还必须同步调整业务层设计:
- 把原本设置了
EXPIRE的 key 改为永久不过期,并在 value 中加入逻辑过期字段(如{"exp": 1743790260, "data": "..."})) - 配置
maxmemory-policy allkeys-lfu,同时开启lfu-log-factor 10和lfu-decay-time 1,否则高频热点 key 可能长期占用内存而无法被有效淘汰 - 需要注意,LFU 计数器只会在 key 被读取时更新;如果 key 首次写入后一直没有访问,就不会进入实际的淘汰排序依据中
- 每个 key 会额外存储 16bit 计数器,因此内存开销相比
volatile-lru大约高出 15%,上线前应通过压测进行验证
淘汰策略配错的典型错误现象
如果只设置了 maxmemory,却没有配置 maxmemory-policy,那么 Redis 默认会使用 noeviction 策略。最终常见表现如下:
- 当内存被打满后,所有写命令都会直接返回
(error) OOM command not allowed when used memory > 'maxmemory' - 业务层收到的是明确报错,而不是平滑淘汰,这种情况不属于“性能抖动”,而是服务级别的中断
- 使用
volatile-ttl处理 session 类数据时,如果 TTL 全部统一设置为 60s,容易引发整点式过期风暴 - 对于强时效数据(如秒杀 token)如果误用了
allkeys-lfu,冷 key 可能无法被及时清理,反而持续挤占热数据的内存空间
真正难解决的往往不是 Redis 淘汰策略本身,而是业务语义与淘汰机制之间的错配。比如一个 key 是否应该被淘汰,本质上应由业务逻辑决定,而不能完全依赖 Redis 自动判断。
