如何统计Redis中各Spring @Cacheable独立缓存值的命中率?
单缓存命名空间命中率统计方案
Spring Cache 整合 Redis 时,@Cacheable的value属性对应缓存命名空间,默认生成的Redis键格式为{value}::{自定义key},比如API1的所有缓存键都会以API1::为前缀,基于这个规则就可以单独统计对应缓存的命中率,以下是三种常用实现方案:
方案1:Spring切面埋点统计(推荐)
无需修改Redis配置,性能损耗低,适合生产环境使用:
- 自定义AOP切面拦截所有标注
@Cacheable的方法,匹配目标缓存命名空间(比如API1) - 每次请求时先生成和Spring Cache规则一致的缓存键,判断键是否存在,分别累加命中、未命中计数
- 命中率计算公式:命中率 = 命中次数 ÷ (命中次数 + 未命中次数) × 100%
核心示例代码如下:
@Aspect @Component public class CacheStatAspect { // 可替换为Redis的原子计数实现分布式场景统计 private final AtomicInteger api1Hit = new AtomicInteger(0); private final AtomicInteger api1Miss = new AtomicInteger(0); @Autowired private StringRedisTemplate redisTemplate; @Autowired private KeyGenerator keyGenerator; // 直接注入你项目中配置的Spring Cache KeyGenerator @Around("@annotation(cacheable)") public Object around(ProceedingJoinPoint pjp, Cacheable cacheable) throws Throwable { List<String> cacheNames = Arrays.asList(cacheable.value()); if (cacheNames.contains("API1")) { Object generateKey = keyGenerator.generate(pjp.getTarget(), pjp.getSignature(), pjp.getArgs()); String key = "API1::" + generateKey; if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) { api1Hit.incrementAndGet(); } else { api1Miss.incrementAndGet(); } } return pjp.proceed(); } // 对外暴露命中率查询接口 public double getApi1HitRate() { int total = api1Hit.get() + api1Miss.get(); return total == 0 ? 0D : (double) api1Hit.get() / total * 100; } }
方案2:Redis键空间通知实时统计
适合不需要修改业务代码的场景,需要调整Redis配置:
- 开启Redis键空间的命中、未命中事件通知,执行命令:
redis-cli CONFIG SET notify-keyspace-events KhKm - 编写事件监听程序,过滤前缀为
API1::的键对应的命中、未命中事件,分别累加计数后计算命中率
注意:该方案会让Redis每个键访问都产生事件通知,大流量场景下会增加Redis额外性能开销,不建议高并发生产环境使用。
方案3:临时离线统计
适合不需要实时数据、偶尔抽查的场景:
- 生产环境使用scan命令统计当前
API1命名空间总键数:redis-cli --scan --pattern "API1::*" | wc -l - 配合
OBJECT IDLETIME 键名命令统计指定时间窗口内键的访问频次,结合总请求量即可计算对应周期的命中率
注意:禁止在生产环境使用
KEYS命令匹配键,会阻塞Redis主线程导致服务不可用。
内容的提问来源于stack exchange,提问作者user16718130
相关产品推荐
相关产品推荐

