应直接用keyspace_hits和keyspace_misses计算实时命中率,因info中的hit_rate仅为临时近似值且不更新,无法反映动态变化。

怎么用 Redis INFO 命令实时抓取命中率数据
Redis 本身不提供「按时间窗口聚合」的命中率报表,但 INFO stats 里有现成的累计计数:keyspace_hits 和 keyspace_misses。直接除一下就能算出当前总命中率,但要注意——这是自启动以来的累加值,不是最近 1 分钟或 5 分钟的动态指标。
实操建议:
- 用
redis-cli INFO stats | grep -E "(keyspace_hits|keyspace_misses)"快速验证数据是否在增长 - 如果服务重启频繁,累加值意义不大,得配合外部时序存储(比如 Prometheus)做差值计算
-
keyspace_hits只统计GET/EXISTS等明确查 key 的命令,HGETALL、LRANGE这类不触发 keyspace hit,别误当成「全量读命中」 - 某些 Redis 代理(如 Twemproxy)或客户端重试逻辑会重复发请求,导致
keyspace_hits虚高,需结合客户端日志交叉比对
为什么不能只看 info 中的 hit_rate 字段
INFO stats 输出里确实有个 hit_rate 行,但它只是个近似值:Redis 内部用整型计数器做除法后截断为小数点后 2 位再拼字符串,**不参与后续计算,也不更新频率可控**。更关键的是,它只在每次执行 INFO 时临时计算一次,不会缓存或采样。
常见错误现象:
- 写监控脚本时直接解析
hit_rate: 0.92,结果发现数值长时间不动,其实是计数器还没变,不是真的稳住 - 用这个字段做告警阈值(比如
hit_rate ),可能漏掉短时抖动——因为抖动还没拉低到累加平均值的水平 - 集群模式下,每个节点的
hit_rate独立计算,简单求平均会掩盖热点分片问题
如何用 MONITOR + Lua 实现带标签的细粒度统计
如果需要区分「用户登录 token 查询」和「商品详情查询」的命中率,靠 INFO 不够。得在业务层埋点,或者用 Redis 的 MONITOR 捕获命令流——但 MONITOR 开销大、不可长期开启;更稳妥的是让客户端在关键读操作前后打标,再用 Lua 脚本原子更新两个计数器。
示例场景:记录「用户中心」相关 key 的命中情况
-- 在 GET 前调用一次(无论是否存在)
EVAL "redis.call('INCR', 'user:hit:total'); if redis.call('EXISTS', KEYS[1]) == 1 then redis.call('INCR', 'user:hit:success') end" 1 user:123
-- 后续用 INCRBY 把 success/total 推到 Redis TimeSeries 或外部 DB
注意点:
- Lua 脚本里不能用
GET后判断再INCR,否则存在竞态——要用EXISTS原子判断 - 高频 key 上频繁执行 EVAL 会影响吞吐,建议只对核心业务路径启用,非核心走采样(比如每 10 次请求统计 1 次)
- 脚本中硬编码 key 前缀(如
user:hit:*)不如用客户端传参,但参数过多易触发 Redis 集群 hash slot 冲突,得提前规划好 tag 维度
Prometheus + redis_exporter 的配置要点
生产环境推荐用 redis_exporter 拉取指标,再由 Prometheus 计算滚动命中率。它的默认采集项就包含 redis_keyspace_hits_total 和 redis_keyspace_misses_total,但要注意几个容易被忽略的配置项:
- 必须设
--redis.addr为单个实例地址,集群模式要开--redis.is-cluster,否则只拉到第一个节点数据 -
redis_exporter默认每 10 秒采一次,如果想算 1 分钟命中率,PromQL 得写rate(redis_keyspace_hits_total[1m]) / (rate(redis_keyspace_hits_total[1m]) + rate(redis_keyspace_misses_total[1m])),不能直接用increase() - 某些旧版 exporter(v1.3 之前)不暴露
keyspace_*指标,需确认日志里有没有INFO stats解析失败提示 - 如果 Redis 启用了 ACL,exporter 用户至少要有
INFO权限,否则指标全为 0,且无报错日志
最麻烦的其实是维度对齐:客户端以为「缓存未命中 = 查 DB」,但 Redis 层看到的 keyspace_misses 还包括 del 后立刻 get、过期 key 被清理等场景,得在应用层补日志才能归因。










