这是驱逐已开始但尚未爆发的典型信号:Redis达maxmemory后每次写入前检查并触发驱逐,消耗CPU和内存带宽,导致ops下降、延迟升高,evicted_keys持续增长。

为什么 INFO memory 显示内存快满,但 redis-cli --stat 看不到明显写入?
这是驱逐(eviction)已开始但尚未爆发的典型信号。Redis 在达到 maxmemory 后不会立刻卡顿,而是每次写入前检查内存、触发驱逐逻辑——这个过程本身要花时间,尤其当驱逐策略是 allkeys-lru 或 volatile-lfu 时,需要扫描、排序、淘汰,CPU 和内存带宽都会被占用。
常见错误现象:used_memory_human 接近 maxmemory_human,mem_fragmentation_ratio > 1.5,同时 evicted_keys 持续增长,但 instantaneous_ops_per_sec 却掉到很低,甚至 latency doctor 报出 “eviction is taking too long”。
- 务必检查
maxmemory-policy:用CONFIG GET maxmemory-policy查,noeviction不会驱逐但直接返回 OOM 错误;allkeys-random开销最小,volatile-lfu最耗 CPU -
evicted_keys是累计值,要看增量:每秒执行一次INFO memory,观察它是否稳定上涨(比如每秒 +500) - 如果
mem_allocator是jemalloc但mem_fragmentation_ratio> 2.0,说明内存碎片严重,驱逐时 malloc/free 更慢,此时光调策略没用,得重启或启用activedefrag yes
怎么定位哪些 key 正在被高频驱逐?
Redis 本身不记录“谁被删了”,但可以通过驱逐行为反推热点 key 的分布特征。真正要查的是“哪些 key 容易被淘汰”,而不是“刚被删了谁”——因为驱逐发生在写入路径上,关键在访问模式和过期设置。
使用场景:业务突然变慢,evicted_keys 暴涨,但监控里没看到大 key 或异常写入流量。
- 先用
MEMORY USAGE抽样检查大 key:MEMORY USAGE user:10086,确认是否存在单个 >1MB 的 value(比如未分片的缓存列表) - 用
SCAN配合TTL批量看过期时间分布:SCAN 0 MATCH "session:*" COUNT 1000→ 对每个结果跑TTL,统计 TTL volatile-* 策略就会频繁扫描它们 - 避免用
KEYS *:它阻塞主线程,在驱逐压力下等于雪上加霜
maxmemory-policy volatile-lru 为什么比 allkeys-lru 更容易卡?
不是算法更复杂,而是数据结构访问模式不同。volatile-lru 要维护两套 LRU 链表:一套是所有带过期时间的 key,另一套是其中“当前未过期”的子集。每次写入都要更新、比较、剪枝,且无法利用 Redis 4.0+ 的近似 LRU 优化(该优化只对 allkeys 生效)。
性能影响明显:在 100 万 volatile key、平均 TTL 60 秒的实例中,volatile-lru 的驱逐延迟可达 allkeys-lru 的 3–5 倍,且随 key 数量非线性上升。
- 如果你的业务里 90% 的 key 都设了
EXPIRE,那volatile-lru实际等价于allkeys-lru,还多一层判断——不如直接切allkeys-lru -
volatile-ttl看似简单(只比 TTL),但它会让 Redis 频繁遍历整个过期字典,高并发下锁竞争剧烈,实测比volatile-lru更容易引发延迟毛刺 - 没有“永远安全”的策略:哪怕
noeviction,客户端收到(error) OOM command not allowed when used memory > 'maxmemory'.后重试逻辑若没退避,也会打满连接数
如何用 redis-cli --latency 和 slowlog 分离驱逐干扰?
--latency 测的是纯事件循环延迟,能暴露驱逐导致的主线程卡顿;slowlog 记的是命令执行时间,但驱逐动作不计入 slowlog——所以 slowlog 里看不到慢,系统却卡,正是驱逐在后台吃资源的铁证。
实操建议:
- 运行
redis-cli --latency -p 6380看最大延迟(注意单位是毫秒),如果 > 100ms 且与evicted_keys上涨时段吻合,基本锁定驱逐问题 -
SLOWLOG GET 5只能辅助排除:如果 slowlog 里全是正常命令(如GET、HGETALL)且耗时 - 开启
latency-monitor-threshold 100(单位 ms),再用LATENCY LATEST查最近一次超阈值事件类型,输出里出现eviction就不用再猜了
真正难处理的,是驱逐和慢命令、大 key、AOF rewrite、RDB save 全部挤在同一时段——这时候 INFO stats 里的 total_commands_processed 增速会断崖下跌,而 instantaneous_input_kbps 却没降,说明网络还在收请求,但 Redis 已经顾不上处理了。










