闡述背景
快取是應對高併發絕對的利器,在很多業務場景允許的情況下,都可以使用快取來提供效能。
既然用了快取,那對快取進行監控必不可少。比如快取載入耗時,新增耗時等。
在 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<K, Object> 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<CacheMonitor> 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,爬蟲等相關資料。