<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>

          沒遇到過這三個(gè)問題都不好意思說(shuō)用過Redis

          共 2387字,需瀏覽 5分鐘

           ·

          2022-06-26 16:46

          緩存是互聯(lián)網(wǎng)應(yīng)用中不可或缺的一部分。而提到緩存,就不得不提它的三個(gè)經(jīng)典問題——緩存穿透、緩存擊穿和緩存雪崩,我稱它們?yōu)榫彺鎲栴}三兄弟。

          緩存的作用主要有兩個(gè):一來(lái)提升訪問速度;二來(lái)保護(hù)數(shù)據(jù)庫(kù)。在業(yè)務(wù)量不大的時(shí)候,通常沒什么大問題。但當(dāng)業(yè)務(wù)量起來(lái)以后,如果緩存使用不合理,三兄弟一定會(huì)如約而至,讓你體驗(yàn)一下現(xiàn)實(shí)的殘酷。

          三兄弟不來(lái)則已,一來(lái)輕則影響系統(tǒng)性能,重則直接拖垮數(shù)據(jù)庫(kù),導(dǎo)致系統(tǒng)癱瘓。因此,我們不可掉以輕心,要防患于未然。


          緩存穿透

          一個(gè)請(qǐng)求到達(dá)服務(wù)器時(shí),正常情況下是按照如下流程進(jìn)行的。


          即按照如下步驟:

          1. 查詢緩存,如果命中則返回

          2. 緩存未命中,則查詢數(shù)據(jù)庫(kù)

          3. 將從數(shù)據(jù)庫(kù)中查詢到的數(shù)據(jù)寫入緩存并返回


          如果每次都是這樣按部就班的處理,倒也相安無(wú)事。但是,凡事就怕但是。但是總會(huì)有例外,假如請(qǐng)求方對(duì)一個(gè)(數(shù)據(jù)庫(kù)中)根本不存在的數(shù)據(jù)進(jìn)行訪問,那么按照上面的流程,緩存就形同虛設(shè)了。因?yàn)椴淮嬖?,所以不?huì)被寫入緩存,這樣請(qǐng)求每次都會(huì)打到數(shù)據(jù)庫(kù),這個(gè)現(xiàn)象就是所謂的「緩存穿透」了。


          如果只是因?yàn)閭€(gè)別請(qǐng)求去查詢不存在的數(shù)據(jù),那其實(shí)也沒什么大事。但緩存穿透通常是伴隨一些「惡意請(qǐng)求」而來(lái),通常是在短時(shí)間內(nèi)涌入大量請(qǐng)求。如果放任不管,就等著數(shù)據(jù)庫(kù)宕機(jī)吧。

          如何解決

          了解了導(dǎo)致緩存穿透的原因,那么解決方案也就明了了。可以從兩個(gè)方面下手:

          • 緩存不存在的記錄

          • 過濾不存在的請(qǐng)求

          啥?不存在的記錄咋緩存?其實(shí)很簡(jiǎn)單,如果數(shù)據(jù)庫(kù)中也查不到,那就將緩存的 value 設(shè)置成 null 即可(注意要根據(jù)業(yè)務(wù)特性設(shè)置合理的過期時(shí)間)。

          過濾不存在的請(qǐng)求,當(dāng)一個(gè)請(qǐng)求到達(dá)服務(wù)器,比如:

          GET /api/user/1

          過濾器會(huì)先判斷該資源是否存在,如果存在則放行,不存在則直接返回,從而起到保護(hù)系統(tǒng)的作用。

          這種方式也有比較成熟的方案。比如布隆過濾器和布谷鳥過濾器(升級(jí)版布隆布隆過濾器)。


          雙重加固

          不管請(qǐng)求不存在資源是有意還是無(wú)意,都不是我們想要的。所以,我們可以設(shè)定一個(gè)訪問頻率,一定時(shí)間內(nèi)頻繁(超出正常用戶的極限)訪問,可以對(duì)請(qǐng)求方加以限制(如 IP 限制)。另外,一些接口可以加入認(rèn)證,必須登錄才能訪問。


          緩存擊穿

          通常情況,我們會(huì)為緩存設(shè)置一個(gè)過期時(shí)間。而如果在一個(gè)資源的緩存過期以后(或者還未來(lái)得及緩存),瞬間涌入大量查詢?cè)撡Y源的請(qǐng)求,那么這些請(qǐng)求就都會(huì)一股腦的奔向數(shù)據(jù)庫(kù),這時(shí),我們的數(shù)據(jù)庫(kù)可就慘了,可能秒秒鐘掛掉。這種情況我們稱之為緩擊穿。


          如何解決

          要解決緩存擊穿也有兩種思路:

          • 永不過期

          • 加鎖

          先看第一種,短時(shí)間內(nèi)被大量訪問的通常是熱點(diǎn)資源,針對(duì)這類資源我們可以不設(shè)置過期時(shí)間(永不過期),當(dāng)資源有變化時(shí)通過程序去更新緩存。

          再來(lái)看第二種,我們可以使用加鎖的方式(一般 JVM 級(jí)別的鎖即可)來(lái)避免擊穿。當(dāng)緩存過期之后,進(jìn)來(lái)的請(qǐng)求,先要獲得一把鎖(也就是去數(shù)據(jù)庫(kù)查詢的資格),然后再去查詢數(shù)據(jù)庫(kù),最后將數(shù)據(jù)添加到緩存。這樣就可以保證同一時(shí)刻(一個(gè)服務(wù)實(shí)例)只會(huì)有一個(gè)請(qǐng)求去查庫(kù)了,其他線程等緩存有值以后,再去緩存取。


          加鎖偽代碼示例:

           public String getData() throws InterruptedException {    // 從緩存取值    String result = getFromCache();    // 取到直接返回    if (Objects.nonNull(result)) {        return result;    }
          // 嘗試獲取鎖 if (!lock.tryLock()) { // 加鎖失敗則休息一會(huì) Thread.sleep(10); return getData(); }
          // 加鎖成功則去數(shù)據(jù)庫(kù)取值 result = getFromDB(); // 取回后放入緩存 setFromCache(); return result;}


          緩存雪崩

          緩存雪崩指的是,緩存中大量的 key 在同一時(shí)刻集體過期,導(dǎo)致大量請(qǐng)求涌入到數(shù)據(jù)庫(kù)。

          有人把緩存服務(wù)由于一些原因不可用稱為緩存雪崩,我覺得這么叫不太合適。

          你想象一下什么是雪崩,大量的雪花集體從山上往下跳就是雪崩。那么對(duì)應(yīng)到緩存的場(chǎng)景,我們可以把 Redis 看做是山,而 Redis 里的 key 就是雪花。Redis 中大量的 key 同時(shí)失效,就好比是山上大量的雪花同時(shí)往下掉是一樣的。所以雪崩用來(lái)比喻大量 key 集中失效的情況明顯更貼切。而緩存服務(wù)掛掉應(yīng)該屬于緩存服務(wù)故障,可以采取緩存集群的方式來(lái)提高可用性。


          如何解決

          要解決緩存雪崩的問題,有兩種思路:

          • 分散過期時(shí)間

          • 永不過期

          分散過期時(shí)間很容易想到,既然雪崩是因?yàn)?key 集體過期導(dǎo)致的,那么把它們過期的時(shí)間分散開就可以避免這種問題了。

          另一種思路,跟解決緩存擊穿一樣,將緩存設(shè)置為永不過期。


          永不過期的方案有一定的局限性,要看具體的業(yè)務(wù),不能粗暴的將所有緩存都設(shè)置成不過期。


          總結(jié)

          每種技術(shù)方案都有其適用的業(yè)務(wù)場(chǎng)景,也都有其局限性。沒有一個(gè)方案能夠應(yīng)對(duì)所有問題,合適即是好。但從上面的方案中還是能看到一些通用的思想的,比如:盡早返回。咋理解呢?就是讓調(diào)用鏈盡量的短,能攔在應(yīng)用服務(wù)之前的絕不放行(布隆過濾);能從緩存取到的絕不再去查庫(kù)。

          - 完 -


          更多獨(dú)家精彩內(nèi)容盡在《Spring Boot趣味實(shí)戰(zhàn)課》一書中。

          掃碼了解本書詳情!

           

          如果喜歡本文
          歡迎 在看留言分享至朋友圈 三連

           熱文推薦  




          ▼點(diǎn)擊閱讀原文,了解本書詳情~

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

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  欧美后门菊门交 | 蜜桃视频人妻 | 爱爱网址银 | 天堂综合精品无码 | 国产无码一级视频 |