180705-一個簡單的冪等工具類實現
阿新 • • 發佈:2018-07-06
scheduled check final https 內存問題 fault 可能 使用 關系
一個簡單的冪等工具類
在日常的工作中,業務的去重冪等場景屬於比較常見的需求,一般來講簡單的冪等工具類可以基於內存或者基於redis進行,本篇簡單介紹下,如何使用Guava的緩存來實現一個冪等工具類
I. 基本思路與實現
利用Guava的內存緩存來緩存,如果執行完畢,則在緩存中添加一個標識,每次執行之前,判斷是否執行過,從而實現簡單的冪等邏輯
1. 基本實現
基於此,一個簡單的工具來就出爐了
public static final String NOT_HIT_TAG = "UNHIT_TAG"; private static LoadingCache<String, Object> idempotentCache = CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() { @Override public Object load(String key) throws Exception { return NOT_HIT_TAG; } }); public static Object getObject(String uuid) { return idempotentCache.getUnchecked(uuid); }
上面的代碼比較簡單,這個冪等工具類,key為唯一標識,value為上次計算的結果,因此在下次再次執行時,直接拿這個結果即可,適用於需要獲取計算結果作為他用的業務場景中。那麽在實際使用中,直接這麽用是否可行?
答案卻是不行,在實際使用的時候,有幾個地方需要註意
- 如果某次計算結果返回的null怎麽辦?
- 內存是否會爆掉?
2. null值問題
針對返回結果為null的場景,也好解決,就是利用一個符號來代替null,簡單的變形如下
public static final String NOT_HIT_TAG = "UNHIT_TAG"; public static final String NULL_TAG = "NULL_TAG"; private static LoadingCache<String, Object> idempotentCache = CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() { @Override public Object load(String key) throws Exception { return NOT_HIT_TAG; } }); public static Object getObject(String uuid) { Object obj = idempotentCache.getUnchecked(uuid); if (obj instanceof String) { if (NULL_TAG.equals(obj)) { return null; } } return obj; } public static void putObject(String uuid, Object val) { if (val == null) { val = NULL_TAG; } idempotentCache.put(uuid, val); }
在上面使用中,有一點需要註意,在取出數據之後,首先判斷下是否為未命中狀態?為什麽未命中要這麽幹?而言看博文
- 180613-GuavaCache返回Null的註意事項
3. 內存問題
雖然上面設置了失效時間為3min,但在jdk8的場景下,很容易發現內存瘋狂上漲,不見到有回收? why?這塊可能與gauva的內存回收機制有關系,因為jdk8取消了永久代,使用了元空間,當沒有設最大值時,會一直上漲,使用系統的內存
簡單的解決方案就是主動回收掉無效的數據
public static final String NOT_HIT_TAG = "UNHIT_TAG"; public static final String NULL_TAG = "NULL_TAG"; private static LoadingCache<String, Object> idempotentCache = CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build(new CacheLoader<String, Object>() { @Override public Object load(String key) throws Exception { return NOT_HIT_TAG; } }); public static Object getObject(String uuid) { Object obj = idempotentCache.getUnchecked(uuid); if (obj instanceof String) { if (NULL_TAG.equals(obj)) { return null; } } return obj; } public static void putObject(String uuid, Object val) { if (val == null) { val = NULL_TAG; } idempotentCache.put(uuid, val); } public static void remove(String uuid) { idempotentCache.invalidate(uuid); } public static void registerScheduleClearTask() { ScheduledExecutorService task = Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("idempotent")); task.scheduleAtFixedRate(() -> idempotentCache.cleanUp(), 1, 1, TimeUnit.MINUTES); }
II. 其他
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛
2. 聲明
盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840
3. 掃描關註
180705-一個簡單的冪等工具類實現