1. 如何通過(guò)緩存來(lái)提升系統(tǒng)性能

        共 2870字,需瀏覽 6分鐘

         ·

        2021-07-13 23:08

        緩存

        在系統(tǒng)中最消耗性能的地方就是對(duì)數(shù)據(jù)庫(kù)的訪問了,一般來(lái)說(shuō),增、刪、改操作不會(huì)出現(xiàn)什么性能問題,除非索引太多,并且數(shù)據(jù)量有十分龐大的情況下,這三個(gè)操作才會(huì)導(dǎo)致性能問題。一般可以限制單表索引的數(shù)量來(lái)提升性能,比如單表的索引數(shù)量不能超過(guò)5個(gè)。

        絕大多數(shù)情況下,性能問題都出在查詢上,select操作提供了非常豐富的語(yǔ)法,這些語(yǔ)法包括函數(shù),子查詢,like子句,where子句等,這些查詢都是非常消耗性能的。大部分應(yīng)用都是讀多寫少的應(yīng)用,所以查詢慢的問題會(huì)被放大了,導(dǎo)致慢查詢成為了系統(tǒng)性能的瓶頸,這是就需要用到緩存來(lái)提高系統(tǒng)的性能。

        緩存為什么能提供系統(tǒng)性能?

        緩存通過(guò)減少系統(tǒng)對(duì)數(shù)據(jù)庫(kù)的訪問量來(lái)提高系統(tǒng)性能。試想一下,如果有100個(gè)請(qǐng)求同時(shí)請(qǐng)求同一個(gè)數(shù)據(jù),沒有加緩存之前,需要訪問100次數(shù)據(jù)庫(kù),而加了緩存之后,可能只需訪問1次數(shù)據(jù)庫(kù),剩下的99個(gè)請(qǐng)求的數(shù)據(jù)從緩存中取,大大的較少了數(shù)據(jù)庫(kù)的訪問量,雖然同樣需要訪問100次,但數(shù)據(jù)庫(kù)的讀取性能和緩存的讀取性能不在一個(gè)級(jí)別上,所以對(duì)系統(tǒng)性能提升顯著。為什么說(shuō)可能需要訪問1次數(shù)據(jù)庫(kù)呢,這個(gè)和過(guò)期有關(guān),后面會(huì)講。

        更新模式

        既然知道了緩存對(duì)系統(tǒng)性能提升顯著,那下面先來(lái)了解一下緩存如何更新吧。

        Cache Aside(推薦)

        這應(yīng)該是最常用的更新模式了,這種模式大致流程如下:

        讀取

        • 如果緩存中沒有,則再?gòu)臄?shù)據(jù)庫(kù)中讀取數(shù)據(jù),得到數(shù)據(jù)之后,放入緩存。
        • 如果緩存中有,取到后直接返回。

        更新

        • 先更新數(shù)據(jù)庫(kù)里的數(shù)據(jù),成功后,讓緩存失效。
        為什么是讓緩存失效而不是更新緩存呢?

        主要是因?yàn)閮蓚€(gè)并發(fā)寫操作導(dǎo)致臟數(shù)據(jù)。試想一下,有兩個(gè)線程A和B,分別要將資源A的值修改為1和2,線程A先到達(dá)數(shù)據(jù)庫(kù)把數(shù)據(jù)更新為1,但還沒更新緩存,由于時(shí)間片用完了,此時(shí)線程B獲得了CPU,并在這期間把數(shù)據(jù)庫(kù)資源A的值和緩存的值都更新為2,線程B結(jié)束后,線程A重新獲得CPU,執(zhí)行更新緩存,把資源A的值改為1,線程A結(jié)束。此時(shí),數(shù)據(jù)庫(kù)中A的值為2,而緩存中A的值為1,數(shù)據(jù)不一致。所以讓緩存失效就不會(huì)有這個(gè)問題,保證緩存中的數(shù)據(jù)和數(shù)據(jù)庫(kù)的保持一致。

        那是不是Cache Aside模式就不會(huì)有并發(fā)問題了呢?

        不是的。比如,一個(gè)讀操作,沒有命中緩存,就去數(shù)據(jù)的讀取數(shù)據(jù)(A=1),此時(shí)一個(gè)寫操作,更新數(shù)據(jù)庫(kù)數(shù)據(jù)(A=2)并讓緩存失效,此時(shí)讀操作把讀取到的數(shù)據(jù)(A=1)寫到緩存中,導(dǎo)致臟數(shù)據(jù)。

        這種情況理論上會(huì)出現(xiàn),但現(xiàn)實(shí)情況中出現(xiàn)的幾率極低。要這種情況出現(xiàn)必須在一個(gè)讀操作發(fā)生時(shí),有一個(gè)并發(fā)寫操作,并且既要讀操作要于寫操作寫入前讀取,又要后于寫操作寫入緩存。滿足這種條件的概率并不大。

        基于出現(xiàn)上面所描述的問題,目前有兩種比較合理的解決方案:

        • 通過(guò)2PC這種保證數(shù)據(jù)的一致性(復(fù)雜);
        • 通過(guò)降低并發(fā)時(shí)臟數(shù)據(jù)的概率,并設(shè)置合理的過(guò)期時(shí)間(簡(jiǎn)單,但存在一定時(shí)間內(nèi)的錯(cuò)誤率,一般可以接受)。

        Read/Write Through

        在這種模式下,對(duì)于應(yīng)用程序來(lái)說(shuō),所有的讀寫請(qǐng)求都是直接和緩存打交道,關(guān)于數(shù)據(jù)庫(kù)的數(shù)據(jù)完全由緩存服務(wù)來(lái)更新(更新同步為同步操作)。

        這種模式下流程就相當(dāng)簡(jiǎn)單了,完全就是對(duì)緩存的讀寫。

        缺點(diǎn):這種模式對(duì)緩存服務(wù)有強(qiáng)依賴性,要求緩存具備高可用性。所以應(yīng)有沒有上一種普遍。

        Write Behind Caching

        其實(shí)這個(gè)模式就是Read/Write Through的一個(gè)變種,區(qū)別就在于前者是異步更新,后者是同步更新。

        既然是異步更新數(shù)據(jù)庫(kù),他的相應(yīng)速度比Read/Write Through還要高,并且還能合并對(duì)同一個(gè)數(shù)據(jù)的多次操作。這個(gè)有點(diǎn)像MySQL的buffer pool的刷盤操作。

        缺點(diǎn):異步就代表數(shù)據(jù)不是強(qiáng)一致性的,還存在數(shù)據(jù)丟失的風(fēng)險(xiǎn),實(shí)現(xiàn)邏輯也較為復(fù)雜。

        設(shè)計(jì)思路

        無(wú)狀態(tài)的服務(wù)

        在分布式系統(tǒng)中,無(wú)狀態(tài)的服務(wù)有利于橫向擴(kuò)展,所以緩存也應(yīng)該獨(dú)立于業(yè)務(wù)服務(wù)在外,設(shè)計(jì)成一個(gè)獨(dú)立的服務(wù),使業(yè)務(wù)服務(wù)變成無(wú)狀態(tài)的。很多公司都選擇是用Redis來(lái)搭建他們的緩存系統(tǒng),取決于其高速的讀寫性能。

        命中率

        一個(gè)緩存服務(wù)的好壞主要看命中率,一般來(lái)說(shuō),命中率保存在80%以上已經(jīng)算很高了,但我們不能為了提高命中率而把數(shù)據(jù)庫(kù)的全部數(shù)據(jù)的寫到緩存了,這個(gè)是不符合緩存的設(shè)計(jì)理念,而且需要極大的內(nèi)存空間。通常來(lái)說(shuō),應(yīng)該只有小部分熱點(diǎn)數(shù)據(jù)寫到緩存。 緩存是通過(guò)犧牲強(qiáng)一致性來(lái)?yè)Q取性能的,并不是所有的業(yè)務(wù)的適合使用緩存。

        有效時(shí)間

        緩存數(shù)據(jù)的有效時(shí)間不易過(guò)短,不易過(guò)長(zhǎng),不易過(guò)于集中。

        • 過(guò)短,會(huì)增加數(shù)據(jù)庫(kù)訪問的次數(shù)。
        • 過(guò)長(zhǎng)容易不使用的數(shù)據(jù)一直停留在緩存中,浪費(fèi)空間,并且一旦產(chǎn)生臟數(shù)據(jù),過(guò)程的有效時(shí)間會(huì)導(dǎo)致臟數(shù)據(jù)遲遲無(wú)法失效,進(jìn)而導(dǎo)致影響更多的業(yè)務(wù)。
        • 過(guò)于集中,會(huì)導(dǎo)致緩存雪崩。

        淘汰策略

        當(dāng)內(nèi)存不足時(shí),緩存系統(tǒng)就要按照淘汰策略,把不適合留在緩存的數(shù)據(jù)淘汰掉,騰出位置給新數(shù)據(jù)。下面就以Redis為例,給出了淘汰策略:

        • noeviction: 不刪除策略, 達(dá)到最大內(nèi)存限制時(shí), 如果需要更多內(nèi)存, 直接返回錯(cuò)誤信息(有極少數(shù)會(huì)例外, 如 DEL )。
        • allkeys-lru: 所有key通用,優(yōu)先刪除最近最少使用(less recently used ,LRU) 的 key。(推薦)
        • volatile-lru: 只限于設(shè)置了 expire 的部分,優(yōu)先刪除最近最少使用(less recently used ,LRU) 的 key。
        • allkeys-random: 所有key通用,隨機(jī)刪除一部分 key。
        • volatile-random: 只限于設(shè)置了 expire 的部分,隨機(jī)刪除一部分 key。
        • volatile-ttl: 只限于設(shè)置了 expire 的部分,優(yōu)先刪除剩余時(shí)間(time to live,TTL) 短的key。

        可根據(jù)項(xiàng)目實(shí)際情況進(jìn)行選擇。

        小結(jié)

        緩存是為了加速數(shù)據(jù)的訪問,在數(shù)據(jù)庫(kù)之上的一直機(jī)制,并非所有業(yè)務(wù)都適合使用緩存,要根據(jù)具體情況選擇更新策略和淘汰策略。

        (感謝閱讀,希望對(duì)你所有幫助)
        來(lái)源:blog.csdn.net/qq_36011946/article/details/104164031

        1. 重裝IDEA再也不愁了,一招搞定同步個(gè)人配置!

        2. 分布式事務(wù)的 6 種解決方案,寫得非常好!

        3. JetBrains 又出了一款新神器,一套代碼適應(yīng)多端!

        4. 關(guān)系型數(shù)據(jù)庫(kù)設(shè)計(jì)要領(lǐng)(值得收藏)

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

        謝謝支持喲 (*^__^*)

        瀏覽 53
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 女人做爰高潮时叫要精免费的视频 | 777av | 成人做爰黄 片视频动漫 | 九九精品在线观看 | 亚洲黄免费 |