不能直接用单次info stats的keyspace_hits和keyspace_misses相除计算实时命中率,必须通过时间窗口内增量(如30秒)计算Δhits/(Δhits+Δmisses);keyspace_hits仅统计对存在的key执行get等读命令的成功次数,不包含exists、过期key读取、scan等场景;redis 7.0+的hit_rate字段依赖至少一次miss且总请求>0,不可靠,应关注增量比率的趋势变化。

直接看 keyspace_hits 和 keyspace_misses 能否反映真实命中率
不能直接用单次 INFO stats 的两个值相除——它们是自 Redis 启动以来的累计计数,不是实时比率。如果你只取一次快照,keyspace_hits / (keyspace_hits + keyspace_misses) 算出来的是“历史平均命中率”,对当前负载无意义。真正要判断“此刻是否健康”,必须采集**时间窗口内的增量**,比如每 10 秒采一次,算 Δhits / (Δhits + Δmisses)。
如何用 redis-cli 正确计算 30 秒滚动命中率
最轻量、无需额外工具的方式就是写个简单循环脚本抓差值:
- 先执行一次
redis-cli INFO stats | grep -E "keyspace_(hits|misses)",记录初始值h1、m1 sleep 30- 再执行同命令,得到新值
h2、m2 - 命中率 =
(h2 - h1) / ((h2 - h1) + (m2 - m1))(注意分母为 0 时跳过)
这个值如果持续低于 0.85(即 85%),就该警惕:要么缓存粒度太细、key 设计不合理,要么 maxmemory 设置过小导致频繁驱逐,也可能是业务请求模式突变(比如冷数据被批量扫)。
keyspace_hits 不包含哪些“命中”?容易误判的场景
它只统计对 **db0~db15 中实际存在的 key 执行 GET/GETEX/HGET 等读命令成功返回值** 的次数。以下情况不会计入 keyspace_hits,但你主观上可能认为“缓存生效”了:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 使用
EXISTS key命令查 key 是否存在——哪怕返回 1,也不算 hit - 对已过期但尚未被惰性删除或定期清理的 key 执行读操作——Redis 返回 nil,记为 miss
- 使用
SCAN遍历 key 空间——不触发任何 keyspace 计数 - 命中的是 Lua 脚本里缓存的局部变量,而非 Redis 实例中的 key
所以如果你的业务大量依赖 EXISTS 做前置判断,或依赖 key 过期机制做状态控制,仅看 keyspace_* 指标会严重低估真实缓存效率。
为什么 hit_rate(calculated) 在 INFO 输出里有时为空
这个字段是 Redis 7.0+ 新增的自动计算值,但它的前提是:必须至少发生过一次 miss,且 keyspace_hits + keyspace_misses > 0。如果实例刚启动、还没处理过任何读请求,或者所有请求都命中(keyspace_misses == 0),Redis 就不会输出该行。不要把它当作稳定指标依赖——它只是 convenience,底层仍得靠你自己算 Δ。
真正关键的不是数字本身多好看,而是波动趋势:如果某次部署后,30 秒命中率从 0.92 骤降到 0.63 且持续 5 分钟以上,那比绝对值更值得立刻排查——这时候大概率是新上线逻辑绕过了缓存,或者 key 命名规则变更导致旧 key 失效。










