RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何使用緩存

科技綠洲 ? 來(lái)源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-08 14:07 ? 次閱讀

緩存技術(shù)被認(rèn)為是減輕服務(wù)器負(fù)載、降低網(wǎng)絡(luò)擁塞、增強(qiáng)Web可擴(kuò)展性的有效途徑之一,其基本思想是利用客戶訪問的時(shí)間局部性(Temproral Locality)原理, 將客戶訪問過(guò)的內(nèi)容在Cache中存放一個(gè)副本,當(dāng)該內(nèi)容下次被訪問時(shí),不必連接到駐留網(wǎng)站,而是由Cache中保留的副本提供。

在企業(yè)Web應(yīng)用中,通過(guò)緩存技術(shù)能夠提高請(qǐng)求的響應(yīng)速度;減少系統(tǒng)IO開銷;降低系統(tǒng)數(shù)據(jù)讀寫壓力...

緩存的意義

首先我們要知道,在我們開發(fā)過(guò)程中,為什么要使用緩存,緩存能夠?yàn)槲覀儙?lái)哪些好處!

優(yōu)點(diǎn)

  • 通過(guò)緩存承載系統(tǒng)壓力,減少對(duì)系統(tǒng)或網(wǎng)絡(luò)資源訪問而引起的性能消耗,在流量較大時(shí)能夠很好地減少系統(tǒng)擁塞
  • 緩存一般都是使用存取非??斓慕M件實(shí)現(xiàn),通過(guò)緩存能夠快速響應(yīng)客戶端請(qǐng)求,從而降低客戶訪問延遲,提審系統(tǒng)響應(yīng)速度
  • 在配備負(fù)載均衡的應(yīng)用架構(gòu)中,通過(guò)緩存靜態(tài)資源能夠有效減少服務(wù)器負(fù)載壓力
  • 當(dāng)下游應(yīng)用故障時(shí),通過(guò)返回緩存數(shù)據(jù)能夠在一定程度上增強(qiáng)應(yīng)用容錯(cuò)性

缺點(diǎn)

  • 緩存數(shù)據(jù)與實(shí)際數(shù)據(jù)不一致問題問題
  • 高并發(fā)場(chǎng)景時(shí)存在緩存擊穿、緩存穿透、緩存雪崩等問題

總的來(lái)說(shuō),緩存主要是針對(duì)高頻訪問但低頻更新的數(shù)據(jù),從而加快服務(wù)器響應(yīng)與原資源訪問壓力

Guava Cache是一個(gè)相對(duì)比較簡(jiǎn)單并且容易理解的本地緩存框架,今天主要以此為開端來(lái)認(rèn)識(shí)并學(xué)習(xí)如何使用緩存

Guava Cache特色

本地緩存我們可以簡(jiǎn)單的理解為Map,將數(shù)據(jù)保存到Map(內(nèi)存)中,下次使用該數(shù)據(jù)時(shí),通過(guò)key直接從Map中取即可。但是使用Map會(huì)有一些幾個(gè)問題需要考慮:

  1. 緩存的容量。不可能無(wú)限制的對(duì)數(shù)據(jù)進(jìn)行緩存,當(dāng)數(shù)據(jù)較大時(shí)占用系統(tǒng)資源會(huì)導(dǎo)致主業(yè)務(wù)受影響
  2. 緩存的清理。有些緩存使用頻率很低,如果一直占用資源也是一種浪費(fèi)
  3. 并發(fā)訪問時(shí)的效率問題。緩存更新時(shí)瞬時(shí)對(duì)系統(tǒng)、網(wǎng)絡(luò)資源的訪問導(dǎo)致故障
  4. 緩存使用情況評(píng)估

當(dāng)然以上問題我們通過(guò)我們對(duì)Map包裝下即可實(shí)現(xiàn),當(dāng)然Guava Cache也就是基于這種思想,底層原理則是基于Map實(shí)現(xiàn),我們看下其有哪些特色:

  • 緩存過(guò)期和淘汰機(jī)制

通過(guò)設(shè)置Key的過(guò)期時(shí)間,包括訪問過(guò)期和創(chuàng)建過(guò)期;設(shè)置緩存容量大小,采用LRU的方式,選擇最近最久的緩存進(jìn)行刪除。

  • 并發(fā)處理能力

Cache主要基于CurrentHashMap實(shí)現(xiàn)線程安全;通過(guò)對(duì)key的計(jì)算,基于分段鎖,提高緩存讀寫效率,降低鎖的粒度,提升并發(fā)能力

  • 更新鎖定

在緩存中查詢某個(gè)key,如果不存在,則查源數(shù)據(jù),并回填緩存。在高并發(fā)下會(huì)出現(xiàn),多次查詢?cè)獢?shù)據(jù)并重復(fù)回填緩存,可能會(huì)造成系統(tǒng)故障,最明顯的DB服務(wù)器宕機(jī),性能下降等。GuavaCache通過(guò)在CacheLoader調(diào)用load方法時(shí),對(duì)同一個(gè)key同一時(shí)刻只會(huì)有一個(gè)請(qǐng)求去讀源數(shù)據(jù)并回填緩存,后面的請(qǐng)求則直接繼續(xù)從緩存讀取,有效阻斷并發(fā)請(qǐng)求對(duì)資源服務(wù)的影響。

  • 集成數(shù)據(jù)源

一般我們?cè)跇I(yè)務(wù)中操作緩存,都會(huì)操作緩存和數(shù)據(jù)源兩部分GuavaCache的get可以集成數(shù)據(jù)源,在從緩存中讀取不到時(shí)可以從數(shù)據(jù)源中讀取數(shù)據(jù)并回填緩存

  • 監(jiān)控統(tǒng)計(jì)

監(jiān)控緩存加載次數(shù)、命中率、失誤率以及數(shù)據(jù)加載時(shí)長(zhǎng)等

API介紹

  • 緩存構(gòu)建
    • ManualCache
      此時(shí)Cache相當(dāng)于一個(gè)Map,對(duì)數(shù)據(jù)進(jìn)行CRUD操作時(shí),需要同步操作緩存Map; 高并發(fā)情況時(shí),可以使用get(k,loader)讀緩存,通過(guò)Cache鎖機(jī)制,防止對(duì)系統(tǒng)資源(DB)的并發(fā)訪問 通過(guò)put方法實(shí)現(xiàn)緩存的存入與更新;
    • LoadingCache
      此時(shí)構(gòu)建的是一個(gè)實(shí)現(xiàn)了Cache接口的LoadingCache,相比ManualCache,提供了緩存回填機(jī)制,即當(dāng)緩存不存在時(shí),會(huì)基于CacheLoader查詢數(shù)據(jù)并將結(jié)果回填到緩存, 在高并發(fā)時(shí),可以有效地基于緩存鎖減少對(duì)系統(tǒng)資源的調(diào)用。此時(shí)僅需要關(guān)注緩存的使用,緩存的更新與存入都是基于CacheLoader實(shí)現(xiàn);
  • 緩存獲取
    • get(k)
      根據(jù)key查詢,沒有則觸發(fā)load;如果load為空則拋出異常
    • getUnchecked(k)
      緩存不存在或返回為null會(huì)拋出檢查異常
    • get(k,loader)
      根據(jù)key查詢,沒有則調(diào)用loader方法,且對(duì)結(jié)果緩存;如果loader返回null則拋出異常,此時(shí)不會(huì)調(diào)用默認(rèn)的load方法
    • getIfPresent(k)
      有緩存則返回,否則返回null,不會(huì)觸發(fā)load
  • 緩存更新
    • put(k,v)
      如果緩存已經(jīng)存在,則會(huì)先進(jìn)行一次刪除
  • 緩存刪除
    • invalidate(k)
      根據(jù)key使緩存失效
    • 過(guò)期
      通過(guò)配置的過(guò)期參數(shù),比如expireAfterAccess、expireAfterWrite、refreshAfterWrite
    • 過(guò)載
      當(dāng)緩存數(shù)據(jù)量超過(guò)設(shè)置的最大值時(shí),根據(jù)LRU算法進(jìn)行刪除
    • 引用
      構(gòu)建緩存時(shí)將鍵值設(shè)置為弱引用、軟引用,基于GC機(jī)制來(lái)清理緩存
  • 統(tǒng)計(jì)
    • hitRate()
      緩存命中率;
    • hitMiss()
      緩存失誤率;
    • loadCount() 加載次數(shù);
    • averageLoadPenalty()
      加載新值的平均時(shí)間,單位為納秒;
    • evictionCount() 緩存項(xiàng)被回收的總數(shù),不包括顯式清除。

Builder配置

配置描述
expireAfterAccess多久沒有讀寫則過(guò)期
expireAfterWrite寫入后多久沒更新自動(dòng)過(guò)期,先刪除,后load
refreshAfterWrite上一次更新后多久自動(dòng)刷新,先reload后刪除,并發(fā)時(shí)會(huì)取到老的數(shù)據(jù)
removalListener設(shè)置緩存刪除監(jiān)聽
initialCapacity緩存初始化大小
concurrencyLevel最大的并發(fā)數(shù),可以理解為并發(fā)線程數(shù)量
maximumSize最大緩存數(shù)量,超過(guò)時(shí)會(huì)根據(jù)策略清除
maximumWeight最大權(quán)重容量數(shù),僅用于確定緩存是否超過(guò)容量
recordStats緩存命中統(tǒng)計(jì)

簡(jiǎn)單示例

  • ManualCache模式
    下面以用戶服務(wù)為例,我們看下如何在增刪改查方法中使用緩存:
private Cache< String, User > cache = CacheBuilder.newBuilder()
            .expireAfterWrite(3, TimeUnit.SECONDS)//寫入多久沒更新自動(dòng)過(guò)期,先刪除,后load
            .removalListener(new RemovalListener< Object, Object >() {
                @Override
                public void onRemoval(RemovalNotification< Object, Object > notification) {
                    LOGGER.info("{} remove {}",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),notification.getKey());
                }
            })
            .initialCapacity(20) //初始化容量
            .concurrencyLevel(10) // 并發(fā)
            .maximumSize(100) //最多緩存數(shù)量
            .recordStats() // 開啟統(tǒng)計(jì)
            .build();

@Override
    public User getUser(String id){
//        緩存不存在時(shí),通過(guò)LocalCache鎖機(jī)制,防止對(duì)數(shù)據(jù)庫(kù)的高頻訪問
       User user;
       try {
           user = cache.get(id,()- > {
               LOGGER.info("緩存不存在,從loader加載數(shù)據(jù)");
               return userDao.get(id);
           });
       } catch (ExecutionException e) {
           throw new RuntimeException(e);
       }
        return user;
    }

    @Override
    public User saveOrUpdateUser(User user){
        userDao.saveOrUpdate(user);
        cache.put(user.getId(),user);
        return user;
    }

    @Override
    public void removeUser(String id){
        userDao.remove(id);
        cache.invalidate(id);
    }
  • LoadingCache模式
private LoadingCache< String, User > cache = CacheBuilder.newBuilder()
            // 省略
            .build(new CacheLoader< String, User >() {
                @Override
                public User load(String key) throws Exception {
                    LOGGER.info("{} load {}",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),key);
                    return userDao.get(key);
                }

                @Override
                public ListenableFuture< User > reload(String key, User oldUser) throws Exception {
                    LOGGER.info("{} reload {}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),key);
                    ListenableFutureTask< User > listenableFutureTask = ListenableFutureTask.create(() - > userDao.get(key));
                    CompletableFuture.runAsync(listenableFutureTask);
                    return listenableFutureTask;
                }
            });

    @SneakyThrows
    @Override
    public User getUser(String id){
        // 緩存不存在或返回為null會(huì)拋出異常
        try {
            return cache.getUnchecked(id);
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public User saveOrUpdateUser(User user){
        cache.invalidate(user.getId());
        return userDao.saveOrUpdate(user);
    }

    @Override
    public void removeUser(String id){
        cache.invalidate(id);
        userDao.remove(id);
    }

總結(jié):第一種寫法更像是前面說(shuō)到的Map,在對(duì)數(shù)據(jù)進(jìn)行CRUD操作時(shí),需要用戶手動(dòng)對(duì)緩存進(jìn)行同步的更新或刪除操作,所以叫ManualCache(手動(dòng)),當(dāng)然Guava Cache對(duì)Map的加強(qiáng)依然有效,比如過(guò)期清除,緩存容量限制。第二種方式寫法差不多,主要是引入了CacheLoader接口,在讀數(shù)據(jù)時(shí)緩存數(shù)據(jù)不存在時(shí),通過(guò)CacheLoader的load方法先寫緩存后返回?cái)?shù)據(jù)

注意

  • expireAfterWrite、refreshAfterWrite的區(qū)別

在refreshAfterWrite導(dǎo)致緩存失效時(shí),并不會(huì)因?yàn)楦戮彺娑枞彺鏀?shù)據(jù)的返回,只不過(guò)是返回老的數(shù)據(jù)

  • 不能緩存null

有時(shí)候?yàn)榱藢⒅禐閚ull的數(shù)據(jù)統(tǒng)一緩存,這樣就不會(huì)因?yàn)闆]有緩存數(shù)據(jù)而訪問數(shù)據(jù)庫(kù)造成壓力

  • 讀寫時(shí)才進(jìn)行刪除

Guava Cache的緩存數(shù)據(jù)刪除是在更新或?qū)懭霑r(shí)才會(huì)觸發(fā),沒有單獨(dú)的調(diào)度服務(wù)完成這一工作

本地緩存

類似的本地緩存還有,有興趣的可以自己嘗試,其實(shí)實(shí)現(xiàn)思想應(yīng)該也差不多

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7002

    瀏覽量

    88940
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    9123

    瀏覽量

    85322
  • 網(wǎng)絡(luò)
    +關(guān)注

    關(guān)注

    14

    文章

    7553

    瀏覽量

    88729
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    239

    瀏覽量

    26669
  • key
    key
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    12826
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    硬盤緩存

    硬盤緩存              緩存(Cache)是SCSI硬盤與外部總線交換數(shù)據(jù)的場(chǎng)所,硬盤先將數(shù)據(jù)傳送到緩存,再由
    發(fā)表于 12-17 14:43 ?1220次閱讀

    硬盤緩存是什么?

    硬盤緩存是什么? 緩存是硬盤內(nèi)部的高速存儲(chǔ)器,硬盤需要通過(guò)它來(lái)完成與外部數(shù)據(jù)總線交換數(shù)據(jù)的過(guò)程。硬盤本身的高速緩存(Cache)
    發(fā)表于 01-22 10:40 ?715次閱讀

    Mybatis緩存之一級(jí)緩存

    本文主要講mybatis的一級(jí)緩存,一級(jí)緩存是SqlSession級(jí)別的緩存。mybatis提供查詢緩存,用于減輕數(shù)據(jù)壓力,提高數(shù)據(jù)庫(kù)性能。mybaits提供一級(jí)
    發(fā)表于 11-27 20:44 ?1226次閱讀
    Mybatis<b class='flag-5'>緩存</b>之一級(jí)<b class='flag-5'>緩存</b>

    渲染中的幀緩存和深度緩存

    渲染涉及大量的緩存,這里緩存只是一個(gè)簡(jiǎn)單的存有像素?cái)?shù)據(jù)的矩形內(nèi)存塊,最重要緩存是幀緩存和深度緩存。
    的頭像 發(fā)表于 05-14 11:44 ?6336次閱讀
    渲染中的幀<b class='flag-5'>緩存</b>和深度<b class='flag-5'>緩存</b>

    什么是Web緩存,HTTP緩存和瀏覽器緩存的區(qū)別

    前端緩存主要是分為HTTP緩存和瀏覽器緩存。其中HTTP緩存是在HTTP請(qǐng)求傳輸時(shí)用到的緩存,主要在服務(wù)器代碼上設(shè)置;而瀏覽器
    發(fā)表于 09-13 04:17 ?9448次閱讀
    什么是Web<b class='flag-5'>緩存</b>,HTTP<b class='flag-5'>緩存</b>和瀏覽器<b class='flag-5'>緩存</b>的區(qū)別

    緩存是什么 為什么需要緩存

    緩存是軟件開發(fā)中一個(gè)非常有用的概念,數(shù)據(jù)庫(kù)緩存更是在項(xiàng)目中必然會(huì)遇到的場(chǎng)景。
    的頭像 發(fā)表于 09-28 02:48 ?1.1w次閱讀
    <b class='flag-5'>緩存</b>是什么 為什么需要<b class='flag-5'>緩存</b>

    緩存的基本原理 緩存的分類

    緩存的主要手段有:瀏覽器緩存、CDN、反向代理、本地緩存、分布式緩存、數(shù)據(jù)庫(kù)緩存。
    發(fā)表于 06-13 12:04 ?4725次閱讀

    緩存如何工作,如何設(shè)計(jì)CPU緩存

    20世紀(jì)80年代,CPU性能有了顯著提升,但這受到板載內(nèi)存訪問速度緩慢增長(zhǎng)的阻礙。隨著這種差異的惡化,工程師們發(fā)現(xiàn)了一種通過(guò)新的設(shè)計(jì)技術(shù)緩存來(lái)解決問題的方法。本文將幫助你進(jìn)一步了解什么是緩存,它如何工作以及如何設(shè)計(jì)CPU緩存
    的頭像 發(fā)表于 11-19 17:23 ?2737次閱讀

    到底是更新緩存還是刪緩存

    如何保證緩存和數(shù)據(jù)庫(kù)一致性,這是一個(gè)老生常談的話題了。 但很多人對(duì)這個(gè)問題,依舊有很多疑惑: 到底是更新緩存還是刪緩存? 到底選擇先更新數(shù)據(jù)庫(kù),再刪除緩存,還是先刪除
    的頭像 發(fā)表于 10-22 17:05 ?5043次閱讀
    到底是更新<b class='flag-5'>緩存</b>還是刪<b class='flag-5'>緩存</b>

    弄懂HTTP緩存機(jī)制及原理

    兩類緩存規(guī)則可以同時(shí)存在,強(qiáng)制緩存優(yōu)先級(jí)高于對(duì)比緩存,也就是說(shuō),當(dāng)執(zhí)行強(qiáng)制緩存的規(guī)則時(shí),如果緩存生效,直接使用
    的頭像 發(fā)表于 01-29 09:38 ?692次閱讀

    聊聊本地緩存和分布式緩存

    本地緩存 :應(yīng)用中的緩存組件,緩存組件和應(yīng)用在同一進(jìn)程中,緩存的讀寫非???,沒有網(wǎng)絡(luò)開銷。但各應(yīng)用或集群的各節(jié)點(diǎn)都需要維護(hù)自己的單獨(dú)緩存,無(wú)
    發(fā)表于 06-11 15:12 ?825次閱讀
    聊聊本地<b class='flag-5'>緩存</b>和分布式<b class='flag-5'>緩存</b>

    mybatis一級(jí)緩存和二級(jí)緩存的原理

    MyBatis是一種輕量級(jí)的持久化框架,它提供了一級(jí)緩存和二級(jí)緩存的機(jī)制來(lái)優(yōu)化數(shù)據(jù)庫(kù)操作性能。一級(jí)緩存是默認(rèn)開啟的,而二級(jí)緩存需要手動(dòng)配置啟用。 一、一級(jí)
    的頭像 發(fā)表于 12-03 11:55 ?1166次閱讀

    Redis緩存預(yù)熱+緩存雪崩+緩存擊穿+緩存穿透要點(diǎn)簡(jiǎn)析

    緩存預(yù)熱就是系統(tǒng)上線后,提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。
    的頭像 發(fā)表于 12-25 09:41 ?901次閱讀
    Redis<b class='flag-5'>緩存</b>預(yù)熱+<b class='flag-5'>緩存</b>雪崩+<b class='flag-5'>緩存</b>擊穿+<b class='flag-5'>緩存</b>穿透要點(diǎn)簡(jiǎn)析

    緩存之美——如何選擇合適的本地緩存?

    Guava cache是Google開發(fā)的Guava工具包中一套完善的JVM本地緩存框架,底層實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)類似于ConcurrentHashMap,但是進(jìn)行了更多的能力拓展,包括緩存過(guò)期時(shí)間設(shè)置、緩存容量設(shè)置、多種淘汰策略、
    的頭像 發(fā)表于 11-17 14:24 ?254次閱讀
    <b class='flag-5'>緩存</b>之美——如何選擇合適的本地<b class='flag-5'>緩存</b>?

    HTTP緩存頭的使用 本地緩存與遠(yuǎn)程緩存的區(qū)別

    HTTP緩存頭是一組HTTP響應(yīng)頭,它們控制瀏覽器和中間代理服務(wù)器如何緩存網(wǎng)頁(yè)內(nèi)容。合理使用HTTP緩存頭可以顯著提高網(wǎng)站的加載速度和性能,減少服務(wù)器的負(fù)載。 1. HTTP緩存頭概述
    的頭像 發(fā)表于 12-18 09:41 ?83次閱讀
    RM新时代网站-首页