应先检查evicted_keys是否持续增长,再结合maxmemory-policy配置与TTL分布判断策略是否匹配;若evicted_keys上涨而used_memory卡在maxmemory附近波动,说明高频淘汰导致“边写边删”,需排查策略误配、TTL缺失或采样参数过小等问题。

直接看 evicted_keys 是否在持续增长,再结合 maxmemory-policy 和 TTL 分布,基本就能定位是不是淘汰策略“选错人”了。
查 evicted_keys 和内存使用斜坡
这是最直观的信号。如果 evicted_keys 每秒都在涨,而 used_memory 却卡在 maxmemory 附近上下小幅波动,说明 Redis 正在高频触发淘汰——不是偶尔腾空间,而是“边写边删”,CPU 和延迟都会被拖住。
-
redis-cli info memory | grep -E "(used_memory|maxmemory|evicted_keys)"看当前值 - 用
redis-cli --stat观察evicted_keys的实时增量,比单次快照更敏感 - 注意:如果
evicted_keys为 0 但used_memory已逼近maxmemory,那问题可能出在“根本没触发淘汰”,比如策略设成了noeviction或volatile-*但大部分 key 没 TTL
确认 maxmemory-policy 是否与数据模型匹配
策略本身没有对错,错的是它和你实际存的数据不搭。比如用了 volatile-lru,但 80% 的 key 是 SET user:123 "xxx" 这种没设过期时间的,那这个策略就形同虚设——它只看带 TTL 的 key,没 TTL 的全免疫,内存迟早打满。
- 用
redis-cli CONFIG GET maxmemory-policy确认当前策略 - 抽样检查 TTL 分布:
redis-cli --scan --pattern "*" | head -n 1000 | xargs -I{} redis-cli ttl {} 2>/dev/null | sort | uniq -c,看返回-1(永不过期)、-2(key 不存在或已过期)和正数的占比 -
allkeys-lru/allkeys-lfu适合纯缓存场景;volatile-*只适合明确区分“临时缓存”和“持久数据”的混合存储,且必须保证临时数据都带 TTL
警惕 maxmemory-samples 过小导致的误淘汰
Redis 的 LRU/LFU 都是近似算法,靠随机采样 maxmemory-samples 个 key 来估算“谁该被淘汰”。默认值是 5,太小了。在 key 数量大、访问模式复杂时,采样偏差会放大,导致刚写入的热 key 被误删,缓存命中率断崖下跌。
- 查当前值:
redis-cli CONFIG GET maxmemory-samples - 生产建议调到 10~20,能显著提升淘汰准确性,代价是每次淘汰多花几微秒 CPU(可忽略)
- 别盲目调太高(比如 100),采样开销会线性上升,且收益边际递减
区分淘汰抖动和过期洪峰
延迟突增不一定来自淘汰。如果恰好大量 key 在同一秒过期,定期删除任务会集中扫描、删除,同样吃 CPU、阻塞主线程。这时 expired_keys 会飙升,而 evicted_keys 不变。
- 对比
info stats里的expired_keys和evicted_keys增速 - 过期洪峰常出现在整点、定时任务后,或业务批量刷缓存后;淘汰抖动则更持续、更随写入压力变化
- 解决过期洪峰要错开 TTL(比如加随机秒数),解决淘汰抖动得调策略或扩容
真正难的不是看出策略错了,而是意识到“策略生效的前提是内存真超了,而超的根源可能是大 key、碎片率高、或者复制积压吃掉了可观内存”——这些不会体现在 evicted_keys 里,但会让淘汰变得更频繁、更无效。











