JetCache埋點(diǎn)的騷操作,不服不行啊
闡述背景
緩存是應(yīng)對(duì)高并發(fā)絕對(duì)的利器,在很多業(yè)務(wù)場(chǎng)景允許的情況下,都可以使用緩存來(lái)提供性能。
既然用了緩存,那對(duì)緩存進(jìn)行監(jiān)控必不可少。比如緩存加載耗時(shí),新增耗時(shí)等。
在 JetCache 中進(jìn)行埋點(diǎn)操作,對(duì)于 Redis 的緩存沒(méi)有問(wèn)題,埋點(diǎn)之后的 Key 是完整的,完整的也就是 Cache 的 name+key,如下圖:

除了對(duì) Redis 的緩存做埋點(diǎn),還對(duì)本地 緩存 Caffeine 也做了埋點(diǎn)操作,然后發(fā)現(xiàn) Caffeine 的埋點(diǎn)有問(wèn)題,問(wèn)題在于 Cache 的 name 丟失了,如下圖:

然后去官方的釘釘群了問(wèn)了下維護(hù)人員,讓我升級(jí)版本。然后我升級(jí)到最新的 2.6.0 還是不行,這不是坑我么 ?!
找出原因
正所謂自己動(dòng)手,豐衣足食。直接看代碼吧,首先看 Redis 為何 Cache name 沒(méi)有丟失,原因是 Redis 的 Config 中有 keyPrefix,如下圖:

然后在對(duì) Redis 進(jìn)行操作的時(shí)候,會(huì)構(gòu)建緩存的 Key,構(gòu)建 Key 的時(shí)候會(huì)帶上 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);
}
}
然后來(lái)看 Caffeine 的 config 中是沒(méi)有 Keyprefix 的,如下圖:

然后在構(gòu)建緩存 Key 的時(shí)候,也就是沒(méi)有 Keyprefix,所以問(wèn)題就出在這里。
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,所以它自然就沒(méi)有 keyPrefix 字段。

解決方案
原因找出來(lái)了,想要解決肯定是可以的。問(wèn)題是這是個(gè)開(kāi)源的框架,不是自己公司內(nèi)部的代碼。不過(guò)也可以直接將源碼克隆下來(lái),進(jìn)行改造,然后打包發(fā)布到自己的私服中去就可以了。
將 EmbeddedCacheConfig 也繼承 ExternalCacheConfig 就可以將 keyPrefix 透?jìng)飨氯?,然后?buildKey 的地方進(jìn)行拼接。
還有一種比較投機(jī)取巧的方案,可以不用改變配置類(lèi)的關(guān)系,在 config 中有 monitors 這個(gè)信息,里面存放的是緩存的監(jiān)控信息,主要是記錄緩存對(duì)應(yīng)的操作類(lèi)型,GET, PUT 這種,然后就是每個(gè)操作的執(zhí)行時(shí)間,操作次數(shù)等一些統(tǒng)計(jì)的信息,最終會(huì)有一個(gè)線程定時(shí)將這些信息輸出到日志中。
所以我們可以通過(guò)獲取 monitors 中的 cacheName 來(lái)臨時(shí)解決這個(gè)問(wèn)題。

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
關(guān)于作者 :尹吉?dú)g,簡(jiǎn)單的技術(shù)愛(ài)好者,《Spring Cloud 微服務(wù)-全棧技術(shù)與案例解析》, 《Spring Cloud 微服務(wù) 入門(mén) 實(shí)戰(zhàn)與進(jìn)階》作者, 公眾號(hào) 猿天地 發(fā)起人。個(gè)人微信 jihuan900 ,歡迎勾搭。
我整理了一份很全的學(xué)習(xí)資料,感興趣的可以微信搜索 「猿天地 」,回復(fù)關(guān)鍵字 「學(xué)習(xí)資料 」獲取我整理好了的Spring Cloud,Spring Cloud Alibaba,Sharding-JDBC分庫(kù)分表,任務(wù)調(diào)度框架XXL-JOB,MongoDB,爬蟲(chóng)等相關(guān)資料。
往期推薦
后臺(tái)回復(fù)?學(xué)習(xí)資料?領(lǐng)取學(xué)習(xí)資料
如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝
