<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 什么是緩存穿透 緩存穿透是指**查詢一個根本不存在的數據,緩存層和存儲層都不會命中**,通常出于容錯的考慮,如果從存儲層查不到數據則不寫入緩存層,整個過程分為下圖3步: * 1)緩存層不命中; * 2)存儲層不命中,不將空結果寫回緩存; * 3)返回空結果; ![](https://img.kancloud.cn/5a/d6/5ad6acc12ecada32e425b840e4c926bd_1296x1296.png) * **緩存穿透帶來的問題:** * ①緩存穿透將導致不存在的數據每次請求都要到存儲層去查詢,**失去了緩存保護后端存儲的意義**; * ②緩存穿透問題可能會**使后端存儲負載加大**,由于很多后端存儲不具備高并發性,甚至可能造成后端存儲宕掉。通常可以在程序中分別統計總調用數、緩存層命中數、存儲層命中數,如果發現大量存儲層空命中,可能就是出現了緩存穿透問題; * **造成緩存穿透的基本原因有兩個:** * 第一,自身業務代碼或者數據出現問題; * 第二,一些惡意攻擊、爬蟲等造成大量空命中; ## 如何發現 1. 業務的響應時間; 2. 業務本身問題; 3. 相關指標:總調用數,緩存層命中數,存儲層命中數; ## 解決方法1--緩存空對象 * **概念**:當第2步存儲層不命中后,**仍然將空對象保留到緩存層中**,之后再訪問這個數據將會從緩存中獲取,這樣就保護了后端數據源; ![](https://img.kancloud.cn/9e/19/9e19cf9ddce2233a37c7b1ef4d9a78d8_347x412.png) **緩存空對象會有兩個問題:** * 第一,空值做了緩存,意味著緩存層中存了更多的鍵,**需要更多的內存空間**(如果是攻擊,問題更嚴重),比較有效的方法是針對這類數據**設置一個較短的過期時間,讓其自動剔除** * 第二,**緩存層和存儲層的數據會有一段時間窗口的不一致,可能會對業務有一定影響。**例如過期時間設置為5分鐘,如果此時存儲層添加了這個數據,那此段時間就會出現緩存層和存儲層數據的不一致,此時可以**利用消息系統或者其他方式清除掉緩存層中的空對象** ``` String get(String key) { // 從緩存中獲取數據 String cacheValue = cache.get(key); // 緩存為空 if (StringUtils.isBlank(cacheValue)) { // 從存儲中獲取 String storageValue = storage.get(key); cache.set(key, storageValue); // 如果存儲數據為空,需要設置一個過期時間(300秒) if (storageValue == null) { cache.expire(key, 60 * 5); } return storageValue; } else { //緩存非空 return cacheValue; } } ``` ## 解決方法2--布隆過濾器 * 如下圖所示,在訪問緩存層和存儲層之前,**將存在的key用布隆過濾器提前保存起來,做第一層攔截** * **例如**:一個推薦系統有4億個用戶id,每個小時算法工程師會根據每個用戶之前歷史行為計算出推薦數據放到存儲層中,但是最新的用戶由于沒有歷史行為,就會發生緩存穿透的行為,為此可以**將所有推薦數據的用戶**做成布隆過濾器。如果布隆過濾器**認為該用戶id不 存在,那么就不會訪問存儲層,在一定程度保護了存儲層** ![](https://img.kancloud.cn/5d/a2/5da2948be284f1c596b8882f59b086d2_506x498.png) * 這種方法**適用于數據命中不高、數據相對固定、實時性低(通常是數據集較大)的應用場景**,代碼維護較為復雜,但是緩存空間占用少 * **備注信息:** * 關于布隆過濾器的介紹可以參閱:[https://blog.csdn.net/qq\_41453285/article/details/106416470](https://blog.csdn.net/qq_41453285/article/details/106416470) * 可以參考:[https://en.wikipedia.org/wiki/Bloom\_filter](https://en.wikipedia.org/wiki/Bloom_filter)可以利用Redis的Bitmaps實現布隆過濾器,GitHub上已經開源了類似的方案,讀者可以進行參考:[https://github.com/erikdubbelboer/redis-lua-scaling-bloom-filter](https://github.com/erikdubbelboer/redis-lua-scaling-bloom-filter) ## # 兩種方案對比 * 前面介紹了緩存穿透問題的兩種解決方法(實際上這個問題是一個開放問題,有很多解決方法),下圖從適用場景和維護成本兩個方面對兩種方案進行分析 ![](https://img.kancloud.cn/e7/45/e745c751c54996f50e133f41fc1755b8_821x200.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看