google的CacheBuilder緩存


適用性:

計算或檢索一個值的代價很高,並且對同樣的輸入需要不止一次獲取值的時候,就應當考慮使用緩存。

 

常用用法:

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(MY_LISTENER)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});

項目中用法:

private LoadingCache<QueryEptAdsInfoVo, String> eptAdsInfoCache =CacheBuilder.newBuilder().softValues().maximumSize(5000).expireAfterWrite(1,TimeUnit.MINUTES)
.build(new CacheLoader<QueryEptAdsInfoVo,String>() {
@Override
public String load(final QueryEptAdsInfoVo tmp) throws Exception {
  //代碼邏輯
}
});

 

之前常用 ConcurrentMap來做緩存,那它們有什么區別呢?

Guava Cache與ConcurrentMap很相似,但也不完全一樣。最基本的區別是ConcurrentMap會一直保存所有添加的元素,直到顯式地移除。相對地,Guava Cache為了限制內存占用,通常都設定為自動回收元素,可設置過期時間。在某些場景下,盡管LoadingCache 不回收元素,它也是很有用的,因為它會自動加載緩存。

 

三種基於時間的清理或刷新緩存數據的方式:
expireAfterAccess: 當緩存項在指定的時間段內沒有被讀或寫就會被回收。
expireAfterWrite:當緩存項在指定的時間段內沒有更新就會被回收。
refreshAfterWrite:當緩存項上一次更新操作之后的多久會被刷新。
 
考慮到時效性,我們可以使用expireAfterWrite,使每次更新之后的指定時間讓緩存失效,然后重新加載緩存。guava cache會嚴格限制只有1個加載操作,這樣會很好地防止緩存失效的瞬間大量請求穿透到后端引起雪崩效應。
     然而,通過分析源碼,guava cache在限制只有1個加載操作時進行加鎖,其他請求必須阻塞等待這個加載操作完成;而且,在加載完成之后,其他請求的線程會逐一獲得鎖,去判斷是否已被加載完成,每個線程必須輪流地走一個“”獲得鎖,獲得值,釋放鎖“”的過程,這樣性能會有一些損耗。這里由於我們計划本地緩存1秒,所以頻繁的過期和加載,鎖等待等過程會讓性能有較大的損耗。
 
     因此我們考慮使用refreshAfterWrite。refreshAfterWrite的特點是,在refresh的過程中,嚴格限制只有1個重新加載操作,而其他查詢先返回舊值,這樣有效地可以減少等待和鎖爭用,所以refreshAfterWrite會比expireAfterWrite性能好。但是它也有一個缺點,因為到達指定時間后,它不能嚴格保證所有的查詢都獲取到新值。了解過guava cache的定時失效(或刷新)原來的同學都知道,guava cache並沒使用額外的線程去做定時清理和加載的功能,而是依賴於查詢請求。在查詢的時候去比對上次更新的時間,如超過指定時間則進行加載或刷新。所以,如果使用refreshAfterWrite,在吞吐量很低的情況下,如很長一段時間內沒有查詢之后,發生的查詢有可能會得到一個舊值(這個舊值可能來自於很長時間之前),這將會引發問題。
 
     可以看出refreshAfterWrite和expireAfterWrite兩種方式各有優缺點,各有使用場景。那么能否在refreshAfterWrite和expireAfterWrite找到一個折中?比如說控制緩存每1s進行refresh,如果超過2s沒有訪問,那么則讓緩存失效,下次訪問時不會得到舊值,而是必須得待新值加載。由於guava官方文檔沒有給出一個詳細的解釋,查閱一些網上資料也沒有得到答案,因此只能對源碼進行分析,尋找答案。經過分析,當同時使用兩者的時候,可以達到預想的效果,這真是一個好消息吶!
 
Guava Cache是單個應用運行時的本地緩存,單機版的緩存。它不把數據存放到文件或外部服務器。如果這不符合你的需求,請嘗試Memcached或Redis


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM