国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

集中式內(nèi)存緩存 Guava Cache

Dean / 392人閱讀

摘要:緩存總體可分為兩種集中式緩存和分布式緩存集中式緩存與分布式緩存的區(qū)別其實(shí)就在于集中與非集中的概念,其對象可能是服務(wù)器內(nèi)存條硬盤等。內(nèi)存條版本緩存集中在一臺(tái)服務(wù)器的一條內(nèi)存條上,為集中式緩存。

背景

緩存的主要作用是暫時(shí)在內(nèi)存中保存業(yè)務(wù)系統(tǒng)的數(shù)據(jù)處理結(jié)果,并且等待下次訪問使用。在日長開發(fā)有很多場合,有一些數(shù)據(jù)量不是很大,不會(huì)經(jīng)常改動(dòng),并且訪問非常頻繁。但是由于受限于硬盤IO的性能或者遠(yuǎn)程網(wǎng)絡(luò)等原因獲取可能非常的費(fèi)時(shí)。會(huì)導(dǎo)致我們的程序非常緩慢,這在某些業(yè)務(wù)上是不能忍的!而緩存正是解決這類問題的神器!

當(dāng)然也并不是說你用了緩存你的系統(tǒng)就一定會(huì)變快,建議在用之前看一下使用緩存的9大誤區(qū)(上) 使用緩存的9大誤區(qū)(下)

緩存在很多系統(tǒng)和架構(gòu)中都用廣泛的應(yīng)用,例如:

CPU緩存

操作系統(tǒng)緩存

HTTP緩存

數(shù)據(jù)庫緩存

靜態(tài)文件緩存

本地緩存

分布式緩存

可以說在計(jì)算機(jī)和網(wǎng)絡(luò)領(lǐng)域,緩存是無處不在的。可以這么說,只要有硬件性能不對等,涉及到網(wǎng)絡(luò)傳輸?shù)牡胤蕉紩?huì)有緩存的身影。

緩存總體可分為兩種 集中式緩存 和 分布式緩存

“集中式緩存"與"分布式緩存"的區(qū)別其實(shí)就在于“集中”與"非集中"的概念,其對象可能是服務(wù)器、內(nèi)存條、硬盤等。比如:

1. 服務(wù)器版本:

緩存集中在一臺(tái)服務(wù)器上,為集中式緩存。

緩存分散在不同的服務(wù)器上,為分布式緩存。

2. 內(nèi)存條版本:

緩存集中在一臺(tái)服務(wù)器的一條內(nèi)存條上,為集中式緩存。

緩存分散在一臺(tái)服務(wù)器的不同內(nèi)存條上,為分布式緩存。

3. 硬盤版本:

緩存集中在一臺(tái)服務(wù)器的一個(gè)硬盤上,為集中式緩存。

緩存分散在一臺(tái)服務(wù)器的不同硬盤上,為分布式緩存。

想了解分布式緩存可以看一下淺談分布式緩存那些事兒。

這是幾個(gè)當(dāng)前比較流行的java 分布式緩存框架5個(gè)強(qiáng)大的Java分布式緩存框架推薦。

而我們今天要講的是集中式內(nèi)存緩存guava cache,這是當(dāng)前我們項(xiàng)目正在用的緩存工具,研究一下感覺還蠻好用的。當(dāng)然也有很多其他工具,還是看個(gè)人喜歡。oschina上面也有很多類似開源的java緩存框架

正文

Guava Cache與ConcurrentMap很相似,但也不完全一樣。最基本的區(qū)別是ConcurrentMap會(huì)一直保存所有添加的元素,直到顯式地移除。相對地,Guava Cache為了限制內(nèi)存占用,通常都設(shè)定為自動(dòng)回收元素。在某些場景下,盡管LoadingCache 不回收元素,它也是很有用的,因?yàn)樗鼤?huì)自動(dòng)加載緩存。

guava cache 加載緩存主要有兩種方式:

cacheLoader

callable callback

cacheLoader

創(chuàng)建自己的CacheLoader通常只需要簡單地實(shí)現(xiàn)V load(K key) throws Exception方法.

cacheLoader方式實(shí)現(xiàn)實(shí)例:

LoadingCache cache = CacheBuilder.newBuilder()
       .build(
           new CacheLoader() {
             public Value load(Key key) throws AnyException {
               return createValue(key);
             }
           });
...
try {
  return cache.get(key);
} catch (ExecutionException e) {
  throw new OtherException(e.getCause());
} 

從LoadingCache查詢的正規(guī)方式是使用get(K)方法。這個(gè)方法要么返回已經(jīng)緩存的值,要么使用CacheLoader向緩存原子地加載新值(通過load(String key) 方法加載)。由于CacheLoader可能拋出異常,LoadingCache.get(K)也聲明拋出ExecutionException異常。如果你定義的CacheLoader沒有聲明任何檢查型異常,則可以通過getUnchecked(K)查找緩存;但必須注意,一旦CacheLoader聲明了檢查型異常,就不可以調(diào)用getUnchecked(K)。

Callable

這種方式不需要在創(chuàng)建的時(shí)候指定load方法,但是需要在get的時(shí)候?qū)崿F(xiàn)一個(gè)Callable匿名內(nèi)部類。

Callable方式實(shí)現(xiàn)實(shí)例:

Cache cache = CacheBuilder.newBuilder()
    .build(); // look Ma, no CacheLoader
...
try {
  // If the key wasn"t in the "easy to compute" group, we need to
  // do things the hard way.
  cache.get(key, new Callable() {
    @Override
    public Value call() throws AnyException {
      return doThingsTheHardWay(key);
    }
  });
} catch (ExecutionException e) {
  throw new OtherException(e.getCause());
} 

而如果加上現(xiàn)在java8里面的Lambda表達(dá)式會(huì)看起來舒服很多

   try {
      cache.get(key,()->{
        return null;
      });
    } catch (ExecutionException e) {
      e.printStackTrace();
    } 

所有類型的Guava Cache,不管有沒有自動(dòng)加載功能,都支持get(K, Callable)方法。這個(gè)方法返回緩存中相應(yīng)的值,或者用給定的Callable運(yùn)算并把結(jié)果加入到緩存中。在整個(gè)加載方法完成前,緩存項(xiàng)相關(guān)的可觀察狀態(tài)都不會(huì)更改。這個(gè)方法簡便地實(shí)現(xiàn)了模式"如果有緩存則返回;否則運(yùn)算、緩存、然后返回"。

當(dāng)然除了上面那種被動(dòng)的加載,它還提供了主動(dòng)加載的方法cache.put(key, value),這會(huì)直接覆蓋掉給定鍵之前映射的值。使用Cache.asMap()視圖提供的任何方法也能修改緩存。但請注意,asMap視圖的任何方法都不能保證緩存項(xiàng)被原子地加載到緩存中。進(jìn)一步說,asMap視圖的原子運(yùn)算在Guava Cache的原子加載范疇之外,所以相比于Cache.asMap().putIfAbsent(K,V)Cache.get(K, Callable) 應(yīng)該總是優(yōu)先使用。

緩存回收

上面有提到 Guava Cache與ConcurrentMap 不一樣的地方在于 guava cache可以自動(dòng)回收元素,這在某種情況下可以更好優(yōu)化資源被浪費(fèi)的情況。

基于容量的回收

當(dāng)緩存設(shè)置CacheBuilder.maximumSize(size)。這個(gè)size是指具體緩存項(xiàng)目的數(shù)量而不是內(nèi)存的大小。而且并不是說數(shù)量大于size才會(huì)回收,而是接近size就回收。

定時(shí)回收

expireAfterAccess(long, TimeUnit):緩存項(xiàng)在給定時(shí)間內(nèi)沒有被讀/寫訪問,則回收。請注意這種緩存的回收順序和基于大小回收一樣。

expireAfterWrite(long, TimeUnit):緩存項(xiàng)在給定時(shí)間內(nèi)沒有被寫訪問(創(chuàng)建或覆蓋),則回 收。如果認(rèn)為緩存數(shù)據(jù)總是在固定時(shí)候后變得陳舊不可用,這種回收方式是可取的。

cache 還提供一個(gè)Ticker方法來設(shè)置緩存失效的具體時(shí)間精度為納秒級。

基于引用的回收

通過使用弱引用的鍵、或弱引用的值、或軟引用的值,Guava Cache可以把緩存設(shè)置為允許垃圾回收:

CacheBuilder.weakKeys():使用弱引用存儲(chǔ)鍵。當(dāng)鍵沒有其它(強(qiáng)或軟)引用時(shí),緩存項(xiàng)可以被垃圾回收。因?yàn)槔厥諆H依賴恒等式(==),使用弱引用鍵的緩存用==而不是equals比較鍵。

CacheBuilder.weakValues():使用弱引用存儲(chǔ)值。當(dāng)值沒有其它(強(qiáng)或軟)引用時(shí),緩存項(xiàng)可以被垃圾回收。因?yàn)槔厥諆H依賴恒等式(==),使用弱引用值的緩存用==而不是equals比較值。

CacheBuilder.softValues():使用軟引用存儲(chǔ)值。軟引用只有在響應(yīng)內(nèi)存需要時(shí),才按照全局最近最少使用的順序回收。考慮到使用軟引用的性能影響,我們通常建議使用更有性能預(yù)測性的緩存大小限定(見上文,基于容量回收)。使用軟引用值的緩存同樣用==而不是equals比較值。

顯式清除

任何時(shí)候,你都可以顯式地清除緩存項(xiàng),而不是等到它被回收:

個(gè)別清除:Cache.invalidate(key)

批量清除:Cache.invalidateAll(keys)

清除所有緩存項(xiàng):Cache.invalidateAll()

這里說一個(gè)小技巧,由于guava cache是存在就取不存在就加載的機(jī)制,我們可以對緩存數(shù)據(jù)有修改的地方顯示的把它清除掉,然后再有任務(wù)去取的時(shí)候就會(huì)去數(shù)據(jù)源重新加載,這樣就可以最大程度上保證獲取緩存的數(shù)據(jù)跟數(shù)據(jù)源是一致的。

移除監(jiān)聽器

不要被名字所迷惑,這里指的是移除緩存的時(shí)候所觸發(fā)的監(jiān)聽器。

請注意,RemovalListener拋出的任何異常都會(huì)在記錄到日志后被丟棄[swallowed]。

 LoadingCache cache = CacheBuilder
    .newBuilder()
    .removalListener(new RemovalListener(){
       @Override
      public void onRemoval(RemovalNotification notification) {
        System.out.println(notification.getKey()+"被移除");
      }
    })

Lambda的寫法:

 LoadingCache cache = CacheBuilder
    .newBuilder()
    .removalListener((notification)->{
      System.out.println(notification.getKey()+"已移除");
    })

警告:默認(rèn)情況下,監(jiān)聽器方法是在移除緩存時(shí)同步調(diào)用的。因?yàn)榫彺娴木S護(hù)和請求響應(yīng)通常是同時(shí)進(jìn)行的,代價(jià)高昂的監(jiān)聽器方法在同步模式下會(huì)拖慢正常的緩存請求。在這種情況下,你可以使用RemovalListeners.asynchronous(RemovalListener, Executor)把監(jiān)聽器裝飾為異步操作。

這里提一下guava cache的自動(dòng)回收,并不是緩存項(xiàng)過期起馬上清理掉,而是在讀或?qū)懙臅r(shí)候做少量的維護(hù)工作,這樣做的原因在于:如果要自動(dòng)地持續(xù)清理緩存,就必須有一個(gè)線程,這個(gè)線程會(huì)和用戶操作競爭共享鎖。此外,某些環(huán)境下線程創(chuàng)建可能受限制,這樣CacheBuilder就不可用了。

相反,我們把選擇權(quán)交到你手里。如果你的緩存是高吞吐的,那就無需擔(dān)心緩存的維護(hù)和清理等工作。如果你的緩存只會(huì)偶爾有寫操作,而你又不想清理工作阻礙了讀操作,那么可以創(chuàng)建自己的維護(hù)線程,以固定的時(shí)間間隔調(diào)用Cache.cleanUp()。ScheduledExecutorService可以幫助你很好地實(shí)現(xiàn)這樣的定時(shí)調(diào)度。

刷新

guava cache 除了回收還提供一種刷新機(jī)制LoadingCache.refresh(K),他們的的區(qū)別在于,guava cache 在刷新時(shí),其他線程可以繼續(xù)獲取它的舊值。這在某些情況是非常友好的。而回收的話就必須等新值加載完成以后才能繼續(xù)讀取。而且刷新是可以異步進(jìn)行的。

如果刷新過程拋出異常,緩存將保留舊值,而異常會(huì)在記錄到日志后被丟棄[swallowed]。

重載CacheLoader.reload(K, V)可以擴(kuò)展刷新時(shí)的行為,這個(gè)方法允許開發(fā)者在計(jì)算新值時(shí)使用舊的值。

   //有些鍵不需要刷新,并且我們希望刷新是異步完成的
LoadingCache graphs = CacheBuilder.newBuilder()
       .maximumSize(1000)
       .refreshAfterWrite(1, TimeUnit.MINUTES)
       .build(
           new CacheLoader() {
             public Graph load(Key key) { // no checked exception
               return getValue(key);
             }

             public ListenableFuture reload(final Key key, Value value) {
               if (neverNeedsRefresh(key)) {
                 return Futures.immediateFuture(value);
               } else {
                 // asynchronous!
                 ListenableFutureTask task = ListenableFutureTask.create(new Callable() {
                   public Graph call() {
                     return getValue(key);
                   }
                 });
                 executor.execute(task);
                 return task;
               }
             }
           });

CacheBuilder.refreshAfterWrite(long, TimeUnit)可以為緩存增加自動(dòng)定時(shí)刷新功能。和expireAfterWrite相反,refreshAfterWrite通過定時(shí)刷新可以讓緩存項(xiàng)保持可用,但請注意:緩存項(xiàng)只有在被檢索時(shí)才會(huì)真正刷新(如果CacheLoader.refresh實(shí)現(xiàn)為異步,那么檢索不會(huì)被刷新拖慢)。因此,如果你在緩存上同時(shí)聲明expireAfterWriterefreshAfterWrite,緩存并不會(huì)因?yàn)樗⑿旅つ康囟〞r(shí)重置,如果緩存項(xiàng)沒有被檢索,那刷新就不會(huì)真的發(fā)生,緩存項(xiàng)在過期時(shí)間后也變得可以回收。

asMap視圖

asMap視圖提供了緩存的ConcurrentMap形式,但asMap視圖與緩存的交互需要注意:

cache.asMap()包含當(dāng)前所有加載到緩存的項(xiàng)。因此相應(yīng)地,cache.asMap().keySet()包含當(dāng)前所有已加載鍵;

asMap().get(key)實(shí)質(zhì)上等同于cache.getIfPresent(key),而且不會(huì)引起緩存項(xiàng)的加載。這和Map的語義約定一致。

所有讀寫操作都會(huì)重置相關(guān)緩存項(xiàng)的訪問時(shí)間,包括Cache.asMap().get(Object)方法和Cache.asMap().put(K, V)方法,但不包括Cache.asMap().containsKey(Object)方法,也不包括在Cache.asMap()的集合視圖上的操作。比如,遍歷Cache.asMap().entrySet()不會(huì)重置緩存項(xiàng)的讀取時(shí)間。

統(tǒng)計(jì)

guava cache為我們實(shí)現(xiàn)統(tǒng)計(jì)功能,這在其它緩存工具里面還是很少有的。

CacheBuilder.recordStats()用來開啟Guava Cache的統(tǒng)計(jì)功能。統(tǒng)計(jì)打開后, Cache.stats()方法會(huì)返回CacheStats對象以提供如下統(tǒng)計(jì)信息:

hitRate():緩存命中率;

averageLoadPenalty():加載新值的平均時(shí)間,單位為納秒;

evictionCount():緩存項(xiàng)被回收的總數(shù),不包括顯式清除。
此外,還有其他很多統(tǒng)計(jì)信息。這些統(tǒng)計(jì)信息對于調(diào)整緩存設(shè)置是至關(guān)重要的,在性能要求高的應(yīng)用中我們建議密切關(guān)注這些數(shù)據(jù), 這里我們就不一一介紹了。

最后

緩存雖然是個(gè)好東西,但是一定不能濫用,一定要根據(jù)自己系統(tǒng)的需求來妥善抉擇。
當(dāng)然 guava 除了cache這塊還有很多其它非常有用的工具。

本文參考:https://github.com/google/guava/wiki/CachesExplained

作者信息
本文系力譜宿云LeapCloud旗下MaxLeap團(tuán)隊(duì)_Service&Infra成員:賈威威 【原創(chuàng)】
賈威威,從事后端開發(fā)已有多年,目前主要負(fù)責(zé)MaxWon服務(wù)端部分功能的開發(fā)與設(shè)計(jì)。
力譜宿云LeapCloud 首發(fā):https://blog.maxleap.cn/archi...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/65117.html

相關(guān)文章

  • 中式內(nèi)存緩存 Guava Cache

    摘要:緩存總體可分為兩種集中式緩存和分布式緩存集中式緩存與分布式緩存的區(qū)別其實(shí)就在于集中與非集中的概念,其對象可能是服務(wù)器內(nèi)存條硬盤等。內(nèi)存條版本緩存集中在一臺(tái)服務(wù)器的一條內(nèi)存條上,為集中式緩存。 背景 緩存的主要作用是暫時(shí)在內(nèi)存中保存業(yè)務(wù)系統(tǒng)的數(shù)據(jù)處理結(jié)果,并且等待下次訪問使用。在日長開發(fā)有很多場合,有一些數(shù)據(jù)量不是很大,不會(huì)經(jīng)常改動(dòng),并且訪問非常頻繁。但是由于受限于硬盤IO的性能或者遠(yuǎn)程...

    KitorinZero 評論0 收藏0
  • 有用的Guava(二)

    摘要:最基本的區(qū)別是會(huì)一直保存所有添加的元素,直到顯式地移除。相對地,為了限制內(nèi)存占用,通常都設(shè)定為自動(dòng)回收元素。消息接收方消息發(fā)起方同步異步注冊事件觸發(fā)事件處理這個(gè)錯(cuò)誤可能是由于中對應(yīng)方法拋出了異常。 緩存 Guava Cache提供了內(nèi)存緩存功能。內(nèi)存緩存需要考慮很多問題,包括并發(fā)問題,緩存失效機(jī)制,內(nèi)存不夠用時(shí)緩存釋放,緩存的命中率,緩存的移除等等。 當(dāng)然這些東西Guava都考慮到了。...

    Tonny 評論0 收藏0
  • Guava 源碼分析(Cache 原理)

    摘要:緩存本次主要討論緩存。清除數(shù)據(jù)時(shí)的回調(diào)通知。具體不在本次的討論范圍。應(yīng)該是以下原因新起線程需要資源消耗。維護(hù)過期數(shù)據(jù)還要獲取額外的鎖,增加了消耗。 showImg(https://segmentfault.com/img/remote/1460000015272232); 前言 Google 出的 Guava 是 Java 核心增強(qiáng)的庫,應(yīng)用非常廣泛。 我平時(shí)用的也挺頻繁,這次就借助日...

    wangxinarhat 評論0 收藏0
  • Guava 源碼分析(Cache 原理)

    摘要:緩存本次主要討論緩存。清除數(shù)據(jù)時(shí)的回調(diào)通知。具體不在本次的討論范圍。應(yīng)該是以下原因新起線程需要資源消耗。維護(hù)過期數(shù)據(jù)還要獲取額外的鎖,增加了消耗。 showImg(https://segmentfault.com/img/remote/1460000015272232); 前言 Google 出的 Guava 是 Java 核心增強(qiáng)的庫,應(yīng)用非常廣泛。 我平時(shí)用的也挺頻繁,這次就借助日...

    Thanatos 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<