必须每秒采样求差才能捕获短时高频淘汰,因evicted_keys是累计值;仅判断是否大于0只能反映历史淘汰,无法识别当前突增压力,需结合expired_keys、keyspace_misses等指标交叉验证内存压力。

如何用定时脚本采集 evicted_keys 增量
直接读 INFO stats 拿到的是累计值,必须做两次采样求差才能判断「这一段时间是否发生了淘汰」。关键不是取值,而是避免漏掉短时高频淘汰(比如 1 秒内淘汰上千 key,但你的采集间隔是 10 秒)。
推荐用 shell + redis-cli 写一个轻量循环脚本,每秒采一次,本地缓存上一次的 evicted_keys 值:
#!/bin/bash
REDIS_CLI="redis-cli -h 127.0.0.1 -p 6379"
LAST_VAL=$( $REDIS_CLI INFO stats 2>/dev/null | grep "^evicted_keys:" | cut -d: -f2 | tr -d '\r\n' )
while true; do
CURR_VAL=$($REDIS_CLI INFO stats 2>/dev/null | grep "^evicted_keys:" | cut -d: -f2 | tr -d '\r\n')
if [[ "$CURR_VAL" =~ ^[0-9]+$ ]] && [[ "$LAST_VAL" =~ ^[0-9]+$ ]]; then
DELTA=$((CURR_VAL - LAST_VAL))
if [ $DELTA -gt 0 ]; then
echo "$(date +%s),evicted,$DELTA" >> /var/log/redis-evict.log
fi
fi
LAST_VAL=$CURR_VAL
sleep 1
done
注意:不要用 cron 每秒跑一次命令——cron 最小粒度是 1 分钟,且并发不可控;用后台 while 循环更稳。
为什么不能只看 evicted_keys 是否大于 0
这个指标一旦增长就永远不归零,只检查「是否 > 0」只能告诉你「历史上发生过淘汰」,完全无法反映当前压力。线上真正要告警的是「最近 N 秒内突增」。
- 例如:某实例
evicted_keys当前是 128,但过去 5 分钟增量为 0 → 安全 - 另一实例同一时刻值为 130,但最近 10 秒涨了 100 → 必须立刻查
maxmemory-policy和热点 key
所以监控系统里务必存储时间序列数据,而非单次快照。
INFO stats 里还有哪些淘汰相关字段要一起看
单看 evicted_keys 容易误判。比如它上涨了,但实际是客户端在大量执行 FLUSHDB 或 DEL,而非内存不足触发淘汰。需要交叉验证:
-
expired_keys:如果它和evicted_keys同步飙升,大概率是设置了大量短 TTL 的 key,而不是内存真不够 -
keyspace_hits/keyspace_misses:miss 率突然升高 +evicted_keys增长 → 可能是缓存穿透或 key 分布异常 -
used_memory_peak_human(在INFO memory中):对比当前used_memory_human,看是否长期贴近峰值,这才是内存压满的信号
别把 evicted_keys 当孤立指标用,它只是内存压力的一个副作用出口。
Python 脚本采集时容易忽略的连接与解析问题
用 redis-py 直接调 client.info("stats") 是最干净的方式,但要注意两个坑:
- 返回字典里键名是
"evicted_keys"(下划线),不是"evicted-keys"或"evictedKeys" - 如果 Redis 开启了密码认证,
ConnectionError可能被吞掉——建议显式捕获并打日志,否则脚本静默失败 - 某些旧版 Redis(evicted_keys 字段,要用
.get("evicted_keys", 0)防 KeyError
真正难的不是取数,而是让这个采集逻辑在 Redis 主从切换、临时超时、配置热更新等场景下不中断、不误报。稳定比功能多更重要。











