<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何通過緩存來提升系統(tǒng)性能?

          共 2805字,需瀏覽 6分鐘

           ·

          2021-07-27 21:04

          微信搜索逆鋒起筆關(guān)注后回復(fù)編程pdf
          領(lǐng)取編程大佬們所推薦的 23 種編程資料!


          來源:blog.csdn.net/qq_36011946/article/details/104164031

          緩存

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

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

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

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

          更新模式

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

          Cache Aside(推薦)

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

          讀取

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

          更新

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

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

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

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

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

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

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

          Read/Write Through

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

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

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

          Write Behind Caching

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

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

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

          設(shè)計思路

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

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

          命中率

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

          有效時間

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

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

          淘汰策略

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

          • noeviction: 不刪除策略, 達(dá)到最大內(nèi)存限制時, 如果需要更多內(nèi)存, 直接返回錯誤信息(有極少數(shù)會例外, 如 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通用,隨機刪除一部分 key。
          • volatile-random: 只限于設(shè)置了 expire 的部分,隨機刪除一部分 key。
          • volatile-ttl: 只限于設(shè)置了 expire 的部分,優(yōu)先刪除剩余時間(time to live,TTL) 短的key。

          可根據(jù)項目實際情況進行選擇。

          小結(jié)

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

          逆鋒起筆是一個專注于程序員圈子的技術(shù)平臺,你可以收獲最新技術(shù)動態(tài)最新內(nèi)測資格BAT等大廠大佬的經(jīng)驗增長自身學(xué)習(xí)資料職業(yè)路線賺錢思維,微信搜索逆鋒起筆關(guān)注!

          編寫高性能 Java 代碼的最佳實踐!

          SQL 性能優(yōu)化梳理

          編寫高性能 Java 代碼的最佳實踐

          一款微信小程序商城項目(附源碼)

          再見 收費的 XShell,我改用國產(chǎn)工具!

          點贊是最大的支持 

          瀏覽 31
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青娱乐精品 | 在线亚洲黄色视频 | 操逼黄色网址 | B日烂了日B | 免费日韩亚洲电影黄色 |