阿里巴巴開源的通用緩存訪問框架JetCache介紹
JetCache是由阿里巴巴開源的通用緩存訪問框架,如果你對Spring Cache很熟悉的話,請一定花一點時間了解一下JetCache,它更好用。
JetCache提供的核心能力包括:
- 提供統一的,類似jsr-107風格的API訪問Cache,並可通過註解創建並配置Cache實例
- 通過註解實現聲明式的方法緩存,支持TTL和兩級緩存
- 分散式緩存自動刷新,分散式鎖 (2.2+)
- 支持非同步Cache API
- Spring Boot支持
- Key的生成策略和Value的序列化策略是可以定製的
- 針對所有Cache實例和方法緩存的自動統計
我們直接看代碼,最簡單的使用場景是這樣的:
public interface UserService { @Cached(expire = 3600, cacheType = CacheType.REMOTE) User getUserById(long userId);}
這和Spring Cache很像,不過@Cached註解原生支持了TTL(超時時間),cacheType有LOCAL/REMOTE/BOTH三種選擇,
分別代表本地內存/遠程Cache Server(例如Redis)/兩級緩存,可根據情況選用,合理的使用LOCAL或BOTH類型可以降低Cache Server的壓力以及我們提供的服務的響應時間。再看個複雜點的例子:
public interface UserService { @Cached(name="userCache-", key="#userId", expire = 3600) User getUserById(long userId); @CacheUpdate(name="userCache-", key="#user.userId", value="#user") void updateUser(User user); @CacheInvalidate(name="userCache-", key="#userId") void deleteUser(long userId);}
第一個例子中我們沒有指定key,JetCache會根據參數自動生成,這個例子我們指定了key,並且展示了緩存的更新和刪除。
自動刷新是JetCache的大殺器:
public interface SummaryService{ @Cached(expire = 3600, cacheType = CacheType.REMOTE) @CacheRefresh(refresh = 1800, stopRefreshAfterLastAccess = 3600, timeUnit = TimeUnit.SECONDS) BigDecimal salesVolumeSummary(int timeId, long catagoryId);}
cacheType為REMOTE或者BOTH的時候,刷新行為是全局唯一的,也就是說,即使應用伺服器是一個集群,也不會出現多個伺服器同時去刷新一個key的情況。
一個key的刷新任務,自該key首次被訪問後初始化,如果該key長時間不被訪問,在stopRefreshAfterLastAccess指定的時間後,相關的刷新任務就會被自動移除,這樣就避免了浪費資源去進行沒有意義的刷新。加在方法上的註解畢竟不能提供最靈活的控制,所以JetCache提供了Cache API,使用起來就像Map一樣:
UserDO user = userCache.get(12345L);userCache.put(12345L, loadUserFromDataBase(12345L));userCache.remove(12345L);userCache.computeIfAbsent(1234567L, (key) -> loadUserFromDataBase(1234567L));
實際上Cache API實現了jsr107規範Cache介面的部分方法,以後的大版本可能會完整實現。
Cache實例可以通過註解創建:
@CreateCache(expire = 100, cacheType = CacheType.BOTH, localLimit = 50)private Cache<Long, UserDO> userCache;
也可以通過和guava cache/caffeine類似的builder來創建:
GenericObjectPoolConfig pc = new GenericObjectPoolConfig();pc.setMinIdle(2);pc.setMaxIdle(10);pc.setMaxTotal(10);JedisPool pool = new JedisPool(pc, "localhost", 6379);Cache<Long, UserDO> userCache = RedisCacheBuilder.createRedisCacheBuilder() .keyConvertor(FastjsonKeyConvertor.INSTANCE) .valueEncoder(JavaValueEncoder.INSTANCE) .valueDecoder(JavaValueDecoder.INSTANCE) .jedisPool(pool) .keyPrefix("userCache-") .expireAfterWrite(200, TimeUnit.SECONDS) .buildCache();
Cache介面支持非同步:
CacheGetResult r = cache.GET(userId);CompletionStage<ResultData> future = r.future();future.thenRun(() -> { if(r.isSuccess()){ System.out.println(r.getValue()); }});
可以實現不嚴格的分散式鎖:
cache.tryLockAndRun("key", 60, TimeUnit.SECONDS, () -> heavyDatabaseOperation());
使用Cache API也可以做自動刷新哦:
@CreateCache@CacheRefresh(timeUnit = TimeUnit.MINUTES, refresh = 60)private Cache<String, Long> orderSumCache;@PostConstructpublic void init(){ orderSumCache.config().setLoader(this::loadOrderSumFromDatabase);}
如果沒有使用註解,用builder一樣也可以做出自動刷新:
Cache<String, Long> orderSumCache = RedisCacheBuilder.createRedisCacheBuilder() ......省略 .refreshPolicy(RefreshPolicy.newPolicy(60, TimeUnit.SECONDS)) .loader(this::loadOrderSumFromDatabase) .buildCache();
當前支持的緩存系統包括以下4個,而且要支持一種新的緩存也是非常容易的:
- Caffeine(基於本地內存)
- LinkedHashMap(基於本地內存,JetCache自己實現的簡易LRU緩存)
- Alibaba Tair(相關實現未在Github開源,在阿里內部Gitlab上可以找到)
- Redis
使用JetCache的系統需求:
- JDK:必須Java 8
- Spring Framework:4.0.8以上,如果不使用註解就不需要
- Spring Boot:1.1.9以上(可選)
更多文檔可以在github的wiki上找到。
有了JetCache,我們就可以更方便的基於統一的介面訪問緩存。有任何問題歡迎在github上與我討論。
原文鏈接
更多技術乾貨敬請關注云棲社區知乎機構號:阿里云云棲社區 - 知乎
推薦閱讀:
※緩存架構
※前端緩存都有哪些方法,有什麼區別?
※高性能 Web 緩存伺服器 nuster 1.7.9.6 發布
※緩存世界中的三大問題及解決方案
※CPU體系結構-Cache