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

          什么是緩存擊穿、雪崩、穿透?

          共 2284字,需瀏覽 5分鐘

           ·

          2020-12-21 15:11

          隨著互聯(lián)網(wǎng)的越來越普及,用戶越來越多,系統(tǒng)性能瓶頸成了越來越熱門的話題。要解決性能問題的技術(shù)手段有很多,比如:緩存、CDN加速、頁面靜態(tài)化、集群、分布式、異步等。

          緩存通常被作為首先技術(shù)方案,簡單而且提升效果明顯,它能夠?qū)⑺俣忍嵘?00倍。那么問題來了,緩存為啥會怎么快呢?

          因?yàn)閭鹘y(tǒng)的數(shù)據(jù)庫操作是基于磁盤的,而緩存是基于內(nèi)存的,內(nèi)存操作和磁盤操作的速度根本不是一個(gè)數(shù)量級的。目前市面上主流的緩存有:redis memcache,這兩個(gè)都是基于內(nèi)存的緩存技術(shù),二者的區(qū)別我在這里暫時(shí)不講。使用緩存的偽代碼一般如下:
          ? ? ? ??
          String?order?=?redisClient.get(key);if(order != null) {???return order;}order?=?db.get(key);redisClient.put(key,order);redisClient.expire(key,3000);return order;

          根據(jù)key獲取數(shù)據(jù),先從緩存中查一下有沒有,如果有則直接返回。如果沒有,再從數(shù)據(jù)庫中查到數(shù)據(jù),然后將數(shù)據(jù)放入緩存中,并且給當(dāng)前key設(shè)置一個(gè)失效時(shí)間,下次再用同樣的key來請求數(shù)據(jù)時(shí),就能夠直接從緩存中查詢到并返回,減少請求數(shù)據(jù)庫的頻次,提升性能,因?yàn)閿?shù)據(jù)庫連接是稀有資源。

          那么問題又來了,為啥要設(shè)置失效時(shí)間,不設(shè)置不行嗎?

          著名的2/8原則告訴我們,經(jīng)常訪問的數(shù)據(jù)集中在20%,而另外的80%屬于不常用數(shù)據(jù)。我們都知道內(nèi)存相當(dāng)于磁盤來說價(jià)格是比較昂貴的,不信你買個(gè)500G的硬盤 和 一個(gè) 500G的內(nèi)存試試。既然這么貴,我們應(yīng)該節(jié)約使用,所以才會有設(shè)置失效時(shí)間這種策略,一旦檢測到某個(gè)key超過了失效時(shí)間,就會將該key從緩存中刪除,可以節(jié)約內(nèi)存。
          ????
          還有個(gè)問題:如果在某個(gè)key失效的時(shí)候,有大量的請求一起過來會怎么樣?

          這就是我今天要給大家講的:擊穿。
          ?? ?
          大量的請求訪問同一個(gè)key,剛好那個(gè)key失效了,那么同一時(shí)間所有的請求,都會穿過緩存,直接請求數(shù)據(jù)庫,此時(shí)的數(shù)據(jù)庫有可能因?yàn)闊o法扛著這么大的并發(fā),直接掛了。

          再問一下:如果大量的請求訪問多個(gè)key,剛好key同時(shí)失效了會怎么樣?

          這就是我今天要給大家講的:雪崩。
          雪崩比上面的擊穿更嚴(yán)重,擊穿只是一個(gè)key失效了,大量請求直接訪問數(shù)據(jù)庫都有可能把數(shù)據(jù)庫搞掛,更何況大量的key同時(shí)失效的場景,數(shù)據(jù)庫面臨的壓力更大,更有可能掛掉。

          接下來的問題:如果大量的用戶請求緩存中不存在的key又會怎么樣?

          這就是我今天要給大家講的:穿透
          有大量的請求訪問時(shí),只有少部分的key在緩存中存在,而有大量的key不存在,這樣請求也會直接訪問到數(shù)據(jù)庫,也會導(dǎo)致數(shù)據(jù)庫扛不住壓力而掛掉。這種情況往往是黑客偽造請求,發(fā)起的惡意攻擊。

          那么,這些問題有沒有解決辦法呢?
          首先,擊穿的解決辦法-加鎖。

          偽代碼如下:
          String order = redisClient.get(key);if(order != null) { return order;}lock() { String order = redisClient.get(key);???if(order?!=?null)?{ return order; } order = db.get(key); redisClient.put(key,order);??redisClient.expire(key,3000);}return order;

          如果根據(jù)key從緩存中查詢不到數(shù)據(jù),需要從數(shù)據(jù)庫中查詢數(shù)據(jù)的時(shí)候,加一把鎖,保證同一時(shí)間只有一個(gè)線程可以查詢數(shù)據(jù)庫,然后把查詢出來的結(jié)果放回到緩存中。這樣其他的線程再用相同的key查詢時(shí),就可以直接從緩存中查到數(shù)據(jù)。這樣就能夠極大的減少數(shù)據(jù)庫的訪問頻次。

          其次,雪崩的解決辦法-?加鎖 + key設(shè)置不同的失效時(shí)間
          加鎖的偽代碼跟上面是一樣的我就不寫了。
          雪崩還有一個(gè)必要條件就是在同一時(shí)間,有大量的key同時(shí)失效。我們只要保證不會出現(xiàn)同一時(shí)間有大量的key同時(shí)失效就可以了,每個(gè)key設(shè)置不同的失效時(shí)間就能解決問題。

          最后,穿透的解決辦法- 業(yè)務(wù)規(guī)則過濾 + 布隆過濾器
          業(yè)務(wù)規(guī)則過濾 可以校驗(yàn) key的長度或者比如前綴SD開頭的等,過濾一批非法數(shù)據(jù)。

          接下來看看布隆過濾器:
          布隆過濾器中會初始化數(shù)據(jù)庫中key的標(biāo)識。如果有大量請求訪問不存在的key時(shí),先通過布隆過濾器檢查一下key在數(shù)據(jù)庫中是否存在,如果存在才允許訪問數(shù)據(jù)庫。如果不存在,則直接返回,這樣就可以過濾掉大量的非法請求。


          推薦閱讀:



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

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

          明天見(??ω??)??


          瀏覽 50
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  俺也去了大香蕉在线 | 欧美网站视频 | 亚洲日韩免费在线观看 | 诱咪一区二区三区四区 | 欧美亚洲天天 |