背景
某银行客户监控告警,Redis命中率低于基准值。
命中率低会影响系统性能。
统计命中率
在 Redis 中,统计命中率(cache hit rate)可以通过分析 Redis 提供的统计信息来完成。具体步骤如下:
-
查看 Redis 统计信息:使用
INFO命令可以获取 Redis 的各种统计信息,包括缓存命中率相关的数据。 -
解析相关字段:从
INFO命令的输出中,我们主要关注两个字段:keyspace_hits:表示键命中的次数。keyspace_misses:表示键未命中的次数。
-
计算命中率:命中率可以通过以下公式计算:
实际操作步骤
- 连接 Redis:可以使用
redis-cli工具或者通过编程语言连接 Redis 实例。 - 执行
INFO命令:获取统计信息。 - 计算命中率:解析返回的数据并计算命中率。
使用 redis-cli 示例
> ./redis-cli INFO stats
这条命令会返回类似以下的输出:
> info stats
# Stats
...
keyspace_hits:1000
keyspace_misses:500
...
我们需要提取 keyspace_hits 和 keyspace_misses 两个值。
使用 Python 代码示例
import redis
# 连接到 Redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 获取统计信息
info = r.info('stats')
# 提取 keyspace_hits 和 keyspace_misses
keyspace_hits = info['keyspace_hits']
keyspace_misses = info['keyspace_misses']
# 计算命中率
if (keyspace_hits + keyspace_misses) > 0:
hit_rate = (keyspace_hits / (keyspace_hits + keyspace_misses)) * 100
else:
hit_rate = 0
print(f"Cache Hit Rate: {hit_rate:.2f}%")
通过上述步骤,你可以轻松统计 Redis 的命中率。关键在于使用 INFO 命令获取统计信息,并根据公式计算命中率。这样可以帮助你了解 Redis 缓存的性能,并进行相应的优化。
实例
项目初次启动,会进行缓存预热,观测redis 的命中率,项目启动前:
> info stats
# Stats
...
keyspace_hits:125
keyspace_misses:86
...
项目启动后:
> info stats
# Stats
...
keyspace_hits:187
keyspace_misses:105
...
可见,预热阶段增加了19次未命中。正常情况下,预热应该全部都是往缓存里set值,为什么会出现未命中呢?
记录未命中的命令
检查源代码, 在代码中进行埋点。对Redis的操作,统一都经过RedisCacheUtil, 所以修改它来记录未命中键:
public class RedisCacheUtil {
public static <T> T hget(String key, String field) throws BizBussinessRuntimeException {
try {
Object v = hashOperations.get(key, field);
if (v == null) {
log.warn("Redis未命中键:" + key);
}
return (T)v;
} catch (Exception e) {
log.error("hget(" + key + ") 操作失败!,msg:" + e.getMessage());
throw new BizBussinessRuntimeException(IErrMsg.ERR_REDIS, "Redis操作失败");
}
}
public static <T> T getObject(String key) throws BizBussinessRuntimeException {
try {
Object v = valueOperations.get(key);
if (v == null) {
log.warn("Redis未命中键:" + key);
}
return (T) v;
} catch (Exception e) {
log.error("getObject(" + key + ") 操作失败!,msg:" + e.getMessage());
throw new BizBussinessRuntimeException(IErrMsg.ERR_REDIS, "Redis操作失败");
}
}
// 其它代码...
}
启动后,查看warn级别的日志, 果然发现了未命中的KEY。
解决
接下来, 打条件断点, 追踪调用链路, 看看是哪里在查缓存
原来是有接口在翻译字典,结果查询字典描述没查到,原因是查询的时候, 没有加租户的条件去查
加上租户参数
再进行测试,发现原来的19次未命中, 变成了1次。
用同样的方法,继续排查,那1次未命中是执行了什么命令,之后也解决掉了。
完成后, 重新启动项目, 持续观察了一段时间,发现缓存未命中次数稳定住了, 不再增加。