当前位置:网站首页>JetCache埋点的骚操作,不服不行啊

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

2020-11-06 01:28:00 尹吉欢

阐述背景

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

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

在 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

  
  1. public byte[] buildKey(K key) {
  2. try {
  3. Object newKey = key;
  4. if (key instanceof byte[]) {
  5. newKey = key;
  6. } else if (key instanceof String) {
  7. newKey = key;
  8. } else if (this.config.getKeyConvertor() != null) {
  9. newKey = this.config.getKeyConvertor().apply(key);
  10. }
  11. return ExternalKeyUtil.buildKeyAfterConvert(newKey, this.config.getKeyPrefix());
  12. } catch (IOException var3) {
  13. throw new CacheException(var3);
  14. }
  15. }

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

图片

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

com.alicp.jetcache.embedded.AbstractEmbeddedCache

  
  1. public Object buildKey(K key) {
  2. if (key == null) {
  3. return null;
  4. } else {
  5. Object newKey = key;
  6. Function<K, Object> keyConvertor = this.config.getKeyConvertor();
  7. if (keyConvertor != null) {
  8. newKey = keyConvertor.apply(key);
  9. }
  10. return newKey;
  11. }
  12. }

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

keyPrefix 定义在 ExternalCacheConfig 中。

图片

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

图片

解决方案

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

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

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

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

图片

  
  1. private String getCacheName() {
  2. List<CacheMonitor> monitors = config.getMonitors();
  3. if (CollectionUtils.isEmpty(monitors)) {
  4. return "";
  5. }
  6. DefaultCacheMonitor cacheMonitor = (DefaultCacheMonitor) monitors.get(0);
  7. String cacheName = cacheMonitor.getCacheName();
  8. return cacheName;
  9. }

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

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

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

版权声明
本文为[尹吉欢]所创,转载请带上原文链接,感谢
http://cxytiandi.com/blog/detail/36498