evicted_keys为0但写入被拒,根本原因不是淘汰未触发,而是volatile-lru/lfu策略仅作用于带ttl的键,若所有key的ttl均为-1(永久键),则策略完全失效,等效于noeviction并报oom错误;须检查ttl分布、补全ex/px或改用allkeys-lru/lfu。

为什么evicted_keys一直为0但写入被拒
这不是淘汰没触发,而是策略根本没生效。最常见原因是用了volatile-lru或volatile-lfu,但业务写入的 key 全都没设 TTL(TTL keyname返回-1)。这类策略只看带过期时间的 key,永久键直接被跳过,结果和noeviction一样报OOM command not allowed when used memory > 'maxmemory'。
- 用
SCAN 0 MATCH * COUNT 1000捞一批 key,再对每个执行TTL,看返回值分布 - 检查代码里所有
SET/HSET调用,是否漏了EX或PX - 如果确实需要保留永久键(如配置项),必须切到
allkeys-lru或allkeys-lfu
CONFIG GET maxmemory-policy显示正确但没效果
配置值只是静态快照,不等于策略正在运行。真正要看的是淘汰行为是否发生——evicted_keys是否在涨,used_memory_peak是否明显高于used_memory。
-
INFO memory里查evicted_keys:0 表示完全没淘汰;持续增长才说明策略活了 - 开慢日志:
CONFIG SET slowlog-log-slower-than 0,再SLOWLOG GET 10,搜evict动作 - 注意
volatile-ttl会快速涨evicted_keys,但它优先删马上过期的 key,容易引发雪崩,不是“有效”而是“激进”
内存明明没满却报 OOM 错误
别急着调大maxmemory,先确认是不是伪 OOM:碎片率高、刚 fork 过、或客户端连接池还在用旧阈值。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 查
mem_fragmentation_ratio:>1.5 就得怀疑是碎片问题,不是真内存不够 - 看
latest_fork_usec时间戳,如果used_memory刚飙升又回落,很可能是 copy-on-write 导致的瞬时虚高 - Jedis/Lettuce 连接池可能缓存了旧的
maxmemory判断逻辑,重启连接池或强制刷新
allkeys-lru 和 allkeys-lfu 实际表现差异在哪
它们都作用于全部 key,但决策依据完全不同,选错会导致热 key 被误删。
-
allkeys-lru靠“最近访问时间”,适合访问有时间局部性(比如用户登录后 30 分钟内高频读 session) -
allkeys-lfu靠“访问频次衰减计数”,适合长尾+强热点(首页 Banner 被查 1000 次,冷门页只查 1 次) -
allkeys-lru是随机采样 5 个 key 淘汰最久未用的,不是全量扫描,小概率误删;allkeys-lfu计数器只有 4 位精度,超高频访问可能溢出
关键点往往藏在数据和策略的匹配关系里:比如用allkeys-lfu存临时 Token,因访问次数少被秒删;或者用volatile-lru存用户资料但忘了加EX,等于白配。










