日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
性能優(yōu)化2.0,新增緩存后,程序的秒開率不升反降

一、前情提要

在上一篇文章中提到,有一個頁面加載速度很慢,是通過緩沖流優(yōu)化的。

創(chuàng)新互聯(lián)建站專注于敘永企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,購物商城網(wǎng)站建設(shè)。敘永網(wǎng)站建設(shè)公司,為敘永等地區(qū)提供建站服務(wù)。全流程按需開發(fā),專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)建站專業(yè)和態(tài)度為您提供的服務(wù)

查詢的時候,會訪問后臺數(shù)據(jù)庫,查詢前20條數(shù)據(jù),按道理來說,這應(yīng)該很快才對。

追蹤代碼,看看啥問題,最后發(fā)現(xiàn)問題有三:

  • 表中有一個BLOB大字段,存儲著一個PDF模板,也就是上圖中的運費模板。
  • 查詢后會將這個PDF模板存儲到本地磁盤。
  • 點擊線上顯示,會讀取本地的PDF模板,通過socket傳到服務(wù)器。

大字段批量查詢、批量文件落地、讀取大文件并進行網(wǎng)絡(luò)傳輸,不慢才怪,這一頓騷操作,5秒能加載完畢,已經(jīng)燒高香了。

經(jīng)過4次優(yōu)化,將頁面的加載時間控制在了1秒以內(nèi),實打?qū)嵉奶嵘顺绦虻拿腴_率。

  • 批量查詢時,不查詢BLOB大字段。
  • 點擊運費查詢時,單獨查詢+觸發(fā)索引,實現(xiàn)“懶加載”。
  • 異步存儲文件。
  • 通過 緩沖流 -> 內(nèi)存映射技術(shù)mmap -> sendFile零拷貝 讀取本地文件。

有一個小伙伴在評論中提到,還可以通過緩存繼續(xù)優(yōu)化,確實是可以的,緩存也是復(fù)用優(yōu)化的一種。

為了提高頁面的加載速度,使用了單條查詢 + 觸發(fā)索引,提高數(shù)據(jù)庫查詢速度。

歸根結(jié)底,還是查詢了數(shù)據(jù)庫,如果不查呢,訪問速度肯定會更快。

這個時候,就用到了緩存,將運費模板存到緩存中。

二、先了解一下,什么是緩存

緩存就是把訪問量較高的熱點數(shù)據(jù)從傳統(tǒng)的關(guān)系型數(shù)據(jù)庫中加載到內(nèi)存中,當(dāng)用戶再次訪問熱點數(shù)據(jù)時,是從內(nèi)存中加載,減少了對數(shù)據(jù)庫的訪問量,解決了高并發(fā)場景下容易造成數(shù)據(jù)庫宕機的問題。

我理解的緩存的本質(zhì)就是一個用空間換時間的一個思想。

提供“緩存”的目的是為了讓數(shù)據(jù)訪問的速度適應(yīng)CPU的處理速度,其基于的原理是內(nèi)存中“局部性原理”。

CPU 緩存的是內(nèi)存數(shù)據(jù),用于解決 CPU 處理速度和內(nèi)存不匹配的問題,比如處理器和內(nèi)存之間的高速緩存,操作系統(tǒng)在內(nèi)存管理上,針對虛擬內(nèi)存 為頁表項使用了一特殊的高速緩存TLB轉(zhuǎn)換檢測緩沖區(qū),因為每個虛擬內(nèi)存訪問會引起兩次物理訪問,一次取相關(guān)的頁表項,一次取數(shù)據(jù),TLB引入來加速虛擬地址到物理地址的轉(zhuǎn)換。

1、緩存有哪些分類

  • 操作系統(tǒng)磁盤緩存,減少磁盤機械操作
  • 數(shù)據(jù)庫緩存,減少文件系統(tǒng) I/O
  • 應(yīng)用程序緩存,減少對數(shù)據(jù)庫的查詢
  • Web 服務(wù)器緩存,減少應(yīng)用程序服務(wù)器請求
  • 客戶端瀏覽器緩存,減少對網(wǎng)站的訪問

2、本地緩存與分布式緩存

本地緩存:在客戶端本地的物理內(nèi)存中劃出一部分空間,來緩存客戶端回寫到服務(wù)器的數(shù)據(jù)。當(dāng)本地回寫緩存達到緩存閾值時,將數(shù)據(jù)寫入到服務(wù)器中。

本地緩存是指程序級別的緩存組件,它的特點是本地緩存和應(yīng)用程序會運行在同一個進程中,所以本地緩存的操作會非???,因為在同一個進程內(nèi)也意味著不會有網(wǎng)絡(luò)上的延遲和開銷。

本地緩存適用于單節(jié)點非集群的應(yīng)用場景,它的優(yōu)點是快,缺點是多程序無法共享緩存。

無法共享緩存可能會造成系統(tǒng)資源的浪費,每個系統(tǒng)都單獨維護了一份屬于自己的緩存,而同一份緩存有可能被多個系統(tǒng)單獨進行存儲,從而浪費了系統(tǒng)資源。

分布式緩存是指將應(yīng)用系統(tǒng)和緩存組件進行分離的緩存機制,這樣多個應(yīng)用系統(tǒng)就可以共享一套緩存數(shù)據(jù)了,它的特點是共享緩存服務(wù)和可集群部署,為緩存系統(tǒng)提供了高可用的運行環(huán)境,以及緩存共享的程序運行機制。

下面介紹一個小編最常用的本地緩存 Guava Cache。

三、Guava Cache本地緩存

1、Google Guava

Google Guava是一個Java編程庫,其中包含了許多高質(zhì)量的工具類和方法。其中,Guava的緩存工具之一是LoadingCache。LoadingCache是一個帶有自動加載功能的緩存,可以自動加載緩存中不存在的數(shù)據(jù)。其實質(zhì)是一個鍵值對(Key-Value Pair)的緩存,可以使用鍵來獲取相應(yīng)的值。

Guava Cache 的架構(gòu)設(shè)計靈感來源于 ConcurrentHashMap,它使用了多個 segments 方式的細粒度鎖,在保證線程安全的同時,支持了高并發(fā)的使用場景。Guava Cache 類似于 Map 集合的方式對鍵值對進行操作,只不過多了過期淘汰等處理邏輯。

Guava Cache對比ConcurrentHashMap優(yōu)勢在哪?

  • Guava Cache可以設(shè)置過期時間,提供數(shù)據(jù)過多時的淘汰機制。
  • 線程安全,支持并發(fā)讀寫。
  • 在緩存擊穿時,GuavaCache 可以使用 CacheLoader 的load 方法控制,對同一個key,只允許一個請求去讀源并回填緩存,其他請求阻塞等待。

2、Loadingcache數(shù)據(jù)結(jié)構(gòu)

  • Loadingcache含有多個Segment,每一個Segment中有若干個有效隊列。
  • 多個Segment之間互不打擾,可以并發(fā)執(zhí)行。
  • 各個Segment的擴容只需要擴自己,與其它的Segment無關(guān)。
  • 設(shè)置合適的初始化容量與并發(fā)水平參數(shù),可以有效避免擴容,但是設(shè)置的太大了,耗費內(nèi)存,設(shè)置的太小,緩存價值降低,需要根據(jù)業(yè)務(wù)需求進行權(quán)衡。
  • Loadingcache數(shù)據(jù)結(jié)構(gòu)和ConcurrentHashMap很相似,ReferenceEntry用于存放key-value。
  • 每一個ReferenceEntry都會存放一個雙向鏈表,采用的是Entry替換的方式。
  • 每次訪問某個元素就將元素移動到鏈表頭部,這樣鏈表尾部的元素就是最近最少使用的元素,替換的復(fù)雜度為o(1),但是訪問的復(fù)雜度還是O(n)。
  • 隊列用于實現(xiàn)LRU緩存回收算法。

3、Loadingcache數(shù)據(jù)結(jié)構(gòu)構(gòu)建流程:

  • 初始化CacheBuilder,指定參數(shù)(并發(fā)級別、過期時間、初始容量、緩存最大容量),使用build()方法創(chuàng)建LocalCache實例。
  • 創(chuàng)建Segment數(shù)組,初始化每一個Segment。
  • 為Segment屬性賦值。
  • 初始化Segment中的table,即一個ReferenceEntry數(shù)組(每一個key-value就是一個ReferenceEntry)。
  1. 根據(jù)之前類變量的賦值情況,創(chuàng)建相應(yīng)隊列,用于LRU緩存回收算法。

4、判斷緩存是否過期

  • expireAfterWrite,在put時更新緩存時間戳,在get時如果發(fā)現(xiàn)當(dāng)前時間與時間戳的差值大于過期時間戳,就會進行l(wèi)oad操作。
  • expireAfterAccess,在expireAfterWrite的基礎(chǔ)上,不管是寫還是讀都會記錄新的時間戳。
  1. refreshAfterWrite,調(diào)用get進行值的獲取的時候才會執(zhí)行reload操作,這里的刷新操作可以通過異步調(diào)用load實現(xiàn)。

5、Loadingcache如何解決緩存穿透

緩存穿透是指在Loadingcache緩存中,由于某些原因,緩存的數(shù)據(jù)無法被正常訪問或處理,導(dǎo)致緩存失去了它的作用。

發(fā)生緩存穿透的原因有很多,比如數(shù)據(jù)量過大、數(shù)據(jù)更新頻繁、數(shù)據(jù)過期、數(shù)據(jù)權(quán)限限制、緩存性能瓶頸等原因,這里不過多糾結(jié)。

(1)expireAfterAcess和expireAfterWrite同步加載

設(shè)置為expireAfterAcess和expireAfterWrite時,在進行g(shù)et的過程中,緩存失效的話,會進行l(wèi)oad操作,load是一個同步加載的操作,如下圖:

如果發(fā)生了緩存穿透,當(dāng)有大量并發(fā)請求訪問緩存時,會有一個線程去同步查詢DB,隨即通過reeatrantLock進入loading等待狀態(tài),其它請求相同key的線程,一部分在waitforvalue,另一部分在reentantloack的阻塞隊列中,等待同步查詢完畢,所有請求都會獲得最新值。

(2)refreshAfterWrite同步加載

如果采用refresh的話,會通過scheduleRefresh方法進行l(wèi)oad,也是一個線程同步獲取DB。

其它線程不會阻塞,性能比expireAfterWrite同步加載高,但是,可能返回新值、也可能返回舊值。

(3)refreshAfterWrite異步加載

當(dāng)加載緩存的線程是異步加載的話,對于請求1,如果在異步結(jié)束前返回,就會返回舊值,反之是新值。

對于其他線程來說,不會被阻塞,直接返回,返回值可能是新值或者是舊值。

Loadingcache沒使用額外的線程去做定時清理和加載的功能,而是依賴于get()請求。

在查詢的時候,進行時間對比,如果使用refreshAfterWrite,在長時間沒有查詢時,查詢有可能會得到一個舊值,我們可以通過設(shè)置refreshAfterWrite(寫刷新,在get時可以同步或異步緩存的時間戳)為5s,將expireAfterWrite(寫過期,在put時更新緩存的時間戳)設(shè)為10s,當(dāng)訪問頻繁的時候,會在每5秒都進行refresh,而當(dāng)超過10s沒有訪問,下一次訪問必須load新值。

四、Redis中如何解決緩存穿透

如果發(fā)生了緩存穿透,可以針對要查詢的數(shù)據(jù),在Redis中插入一條數(shù)據(jù),添加一個約定好的默認值,比如defaultNull。

比如你想通過某個id查詢某某訂單,Redis中沒有,MySQL中也沒有,此時,就可以在Redis中插入一條,存為defaultNull,下次再查詢就有了,因為是提前約定好的,前端也明白是啥意思,一切OK,歲月靜好。

五、使用loadingCache優(yōu)化頁面加載

1、引入pom


    com.google.guava
    guava
    31.0.1-jre

2、初始化LoadingCache

private static LoadingCache loadCache;

public static void initLoadingCache() {
    loadCache = CacheBuilder.newBuilder()
            // 并發(fā)級別設(shè)置為 10,是指可以同時寫緩存的線程數(shù)
            .concurrencyLevel(10)
            // 寫刷新,在get時可以同步或異步緩存的時間戳
            .refreshAfterWrite(5, TimeUnit.SECONDS)
            // 寫過期,在put時更新緩存的時間戳
            .expireAfterWrite(10, TimeUnit.SECONDS)
            // 設(shè)置緩存容器的初始容量為 10
            .initialCapacity(10)
            // 設(shè)置緩存最大容量為 100,超過之后就會按照 LRU 算法移除緩存項
            .maximumSize(100)
            // 設(shè)置要統(tǒng)計緩存的命中率
            .recordStats()
            // 指定 CacheLoader,緩存不存在時,可自動加載緩存
            .build(new CacheLoader() {
                        @Override
                        public String load(String key) throws Exception {
                            // 自動加載緩存的業(yè)務(wù)
                            return "error";
                        }
                    }
            );
}

3、優(yōu)化5:通過LoadingCache緩存模板數(shù)據(jù),在編輯模板后,更新緩存

查詢模板信息后,通過loadCache.put(uuid, pdf);加載到內(nèi)存中,在編輯模板時,更新緩存過期時間,下次獲取模板PDF時,直接從LoadingCache緩存中取,降低數(shù)據(jù)庫訪問壓力,perfect?。。?/p>

這種情況是不適合緩存的,因為模板pdf本來就是一個BLOB大數(shù)據(jù),你把它放內(nèi)存里緩存了,你告訴我,能放幾個?內(nèi)存扛得住嗎?


新聞名稱:性能優(yōu)化2.0,新增緩存后,程序的秒開率不升反降
文章鏈接:http://www.5511xx.com/article/cdcesoo.html