JetCache埋点的骚操作,不服不行啊

猿天地

共 2817字,需浏览 6分钟

 · 2020-08-19

阐述背景

缓存是应对高并发绝对的利器,在很多业务场景允许的情况下,都可以使用缓存来提供性能。

既然用了缓存,那对缓存进行监控必不可少。比如缓存加载耗时,新增耗时等。

在 JetCache 中进行埋点操作,对于 Redis 的缓存没有问题,埋点之后的 Key 是完整的,完整的也就是 Cache 的 name+key,如下图:


除了对 Redis 的缓存做埋点,还对本地 缓存 Caffeine 也做了埋点操作,然后发现 Caffeine 的埋点有问题,问题在于 Cache 的 name 丢失了,如下图:


然后去官方的钉钉群了问了下维护人员,让我升级版本。然后我升级到最新的 2.6.0 还是不行,这不是坑我么 ?!

找出原因

正所谓自己动手,丰衣足食。直接看代码吧,首先看 Redis 为何 Cache name 没有丢失,原因是 Redis 的 Config 中有 keyPrefix,如下图:


然后在对 Redis 进行操作的时候,会构建缓存的 Key,构建 Key 的时候会带上 keyPrefix,所以 Redis 的 Key 是正常的。

com.alicp.jetcache.external.AbstractExternalCache

public byte[] buildKey(K key) {
try {
Object newKey = key;
if (key instanceof byte[]) {
newKey = key;
} else if (key instanceof String) {
newKey = key;
} else if (this.config.getKeyConvertor() != null) {
newKey = this.config.getKeyConvertor().apply(key);
}
return ExternalKeyUtil.buildKeyAfterConvert(newKey, this.config.getKeyPrefix());
} catch (IOException var3) {
throw new CacheException(var3);
}
}

然后来看 Caffeine 的 config 中是没有 Keyprefix 的,如下图:


然后在构建缓存 Key 的时候,也就是没有 Keyprefix,所以问题就出在这里。

com.alicp.jetcache.embedded.AbstractEmbeddedCache

public Object buildKey(K key) {
if (key == null) {
return null;
} else {
Object newKey = key;
Function keyConvertor = this.config.getKeyConvertor();
if (keyConvertor != null) {
newKey = keyConvertor.apply(key);
}
return newKey;
}
}

RedisCacheConfig 继承了 ExternalCacheConfig,ExternalCacheConfig 继承了 CacheConfig。

keyPrefix 定义在 ExternalCacheConfig 中。


而 EmbeddedCacheConfig 只继承了 CacheConfig,所以它自然就没有 keyPrefix 字段。


解决方案

原因找出来了,想要解决肯定是可以的。问题是这是个开源的框架,不是自己公司内部的代码。不过也可以直接将源码克隆下来,进行改造,然后打包发布到自己的私服中去就可以了。

将 EmbeddedCacheConfig 也继承 ExternalCacheConfig 就可以将 keyPrefix 透传下去,然后在 buildKey 的地方进行拼接。

还有一种比较投机取巧的方案,可以不用改变配置类的关系,在 config 中有 monitors 这个信息,里面存放的是缓存的监控信息,主要是记录缓存对应的操作类型,GET, PUT 这种,然后就是每个操作的执行时间,操作次数等一些统计的信息,最终会有一个线程定时将这些信息输出到日志中。

所以我们可以通过获取 monitors 中的 cacheName 来临时解决这个问题。


private String getCacheName() {
List monitors = config.getMonitors();
if (CollectionUtils.isEmpty(monitors)) {
return "";
}
DefaultCacheMonitor cacheMonitor = (DefaultCacheMonitor) monitors.get(0);
String cacheName = cacheMonitor.getCacheName();
return cacheName;
}

功能代码:https://github.com/yinjihuan/kitty

关于作者 :尹吉欢,简单的技术爱好者,《Spring Cloud 微服务-全栈技术与案例解析》, 《Spring Cloud 微服务 入门 实战与进阶》作者, 公众号 猿天地 发起人。个人微信 jihuan900 ,欢迎勾搭。

我整理了一份很全的学习资料,感兴趣的可以微信搜索 猿天地 」,回复关键字 「学习资料 」获取我整理好了的Spring Cloud,Spring Cloud Alibaba,Sharding-JDBC分库分表,任务调度框架XXL-JOB,MongoDB,爬虫等相关资料。



往期推荐



居然说HikariCP连接池慢?是你不会用吧!

跟大佬聊天,被反问Redis6的多线程真的能提高性能吗?

SQL优化不会?推荐4 款工具

干货 | 数据库压力降低90%,携程机票订单缓存系统实践

简直骚操作,ThreadLocal还能当缓存用



后台回复 学习资料 领取学习资料


如有收获,点个在看,诚挚感谢

浏览 35
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报