redis缓存命中率=keyspace_hits/(keyspace_hits+keyspace_misses),需从info stats中提取这两个累计值计算,注意重置、采样及业务语义对齐。

Redis 缓存命中率怎么算?INFO 里哪个字段才管用
命中率不是靠猜,也不是看 ThinkPHP 日志里“缓存已存在”这种模糊提示。真正可靠的来源是 Redis 自身的 INFO 命令输出——但必须盯准 keyspace_hits 和 keyspace_misses 这两个计数器,不是 hits 或 misses(老版本 Redis 里压根没后者)。它们代表的是对实际数据键的读取命中/未命中次数,排除了命令本身错误、连接失败等干扰。
实操建议:
- 在 Redis CLI 中执行
INFO stats,直接找keyspace_hits:和keyspace_misses:行 - 用 PHP 脚本调用时,别依赖
redis->info()返回的全量数组,要明确提取这两个键:$info['keyspace_hits']和$info['keyspace_misses'] - 注意:这两个值是自 Redis 启动以来的累计值,不是实时速率;想看近期趋势,得定期采样做差值计算
ThinkPHP 没暴露命中率接口,怎么从框架层补一手监控
ThinkPHP 的 Cache 类和 Redis 驱动本身不记录或暴露每次操作是否命中,它只负责读写。想拿到应用层视角的命中率,就得在调用链路上“插针”——最稳妥的位置是自定义缓存驱动,或者在中间件里拦截 get 方法。
实操建议:
- 重写
think\cache\driver\Redis,在get()方法开头加逻辑:先用$this->handler->exists($key)判断是否存在,再决定是否计数;注意避免二次网络请求带来的性能损耗 - 更轻量的做法:在业务常用缓存入口(比如封装的
cacheGet()工具函数)里手动统计,用app()->config->get('cache.stats')控制开关,避免上线后常驻开销 - 别在
set()里埋点——它跟命中率无关,反而容易误导分析
为什么 keyspace_hits 突然归零?常见 Redis 重置陷阱
不是缓存全失效了,而是 Redis 实例被重启、主从切换完成、或执行了 CONFIG RESETSTAT。这三个动作都会清空 keyspace_hits 和 keyspace_misses 计数器,导致你看到的命中率瞬间暴跌为 0%,其实是统计断点,不是业务异常。
实操建议:
- 检查 Redis 日志里是否有
DB loaded from disk或Ready to accept connections时间点,比对命中率突变时刻 - 禁止在生产环境随意执行
CONFIG RESETSTAT;如需重置监控指标,应同步通知告警系统跳过该窗口 - 如果用了哨兵或 Cluster,主节点故障转移后,新主节点的计数器也是从 0 开始,这时要看集群维度聚合,不能只盯单点
命中率高≠缓存用得好:警惕“假高”和冷热混用问题
95% 的命中率看着漂亮,但如果 80% 请求都集中在 3 个 key 上,其余 key 全是 miss,说明缓存没覆盖核心路径外的场景;更麻烦的是,当 Redis 内存快满时,它会按 LRU/LFU 清理,但 ThinkPHP 默认配置的 expire 时间可能远长于实际业务热度,导致大量“僵尸 key”占着内存却没人访问。
实操建议:
- 用
redis-cli --bigkeys定期扫大 key,结合OBJECT FREQ查访问频次,识别低频高内存占用项 - ThinkPHP 的
cache.php配置中,别给所有缓存统一设default_expire => 3600;对用户会话、商品详情、配置项这类不同热度的数据,应分组设置不同expire - 监控
mem_used_human和evicted_keys,只要后者持续增长,再高的命中率也掩盖不了淘汰压力
缓存命中率是个结果指标,不是调优终点。真正难的是把 keyspace_hits 的数字,和你代码里每个 Cache::get() 的语义、生命周期、更新时机对上号——这一步,没法靠工具自动完成。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











