緩存設計與優化

来源:https://www.cnblogs.com/dwvfw855/archive/2019/05/23/10912565.html
-Advertisement-
Play Games

緩存的受益與成本 1.受益 加速讀寫 CPU L1/L2/L3 Cache、瀏覽器緩存、Ehcache緩存資料庫結果 降低後端負載 後端伺服器通過前端緩存降低負載:業務端使用Redis降低後端MySQL的負載 加速讀寫 CPU L1/L2/L3 Cache、瀏覽器緩存、Ehcache緩存資料庫結果 ...


緩存的受益與成本

1.受益

  • 加速讀寫

    • CPU L1/L2/L3 Cache、瀏覽器緩存、Ehcache緩存資料庫結果

  • 降低後端負載

    • 後端伺服器通過前端緩存降低負載:業務端使用Redis降低後端MySQL的負載

2.成本

  • 數據不一致:緩存層和數據層有時間視窗不一致問題,和更新策略有關

  • 代碼維護成本:多了一層緩存邏輯

  • 運維成本:例如Redis Cluster

3.使用場景

  • 降低後端負載

    • 對高消耗的SQL:join結果集/分組統計結果緩存

  • 加速請求響應

    • 利用Redis/Memcache優化IO響應時間

  • 大量寫合併為批量寫

    • 入計數器先Redis累加再批量寫DB

 

 

緩存的更新策略

###1.LRU等演算法剔除:例如 maxmemory-policy

淘汰策略含義
noeviction 當記憶體使用達到閾值的時候,所有引起申請記憶體的命令會報錯
allkeys-lru 在主鍵空間中,優先移除最近未使用的key
volatile-lru 在設置了過期時間的鍵空間中,優先移除最近未使用的key
allkeys-random 最主鍵空間中,隨機移除某個key
volatile-random 在設置了過期的鍵空間中,隨機移除某個key
volatile-ttl 在設置了過期時間的鍵空間中,具有更早過期時間的key優先移除

2.超時剔除:例如expire

###3.主動更新:開發控制生命周期

4.兩條建議

  • 低一致性數據:最大記憶體和淘汰策略

  • 高一致性:超時剔除和主動更新結合,最大記憶體和淘汰策略兜底

 

 

緩存粒度問題

  • 通用性:全量屬性更好

  • 占用空間:部分屬性更好

  • 代碼維護:錶面上全量屬性更好

 

 

緩存穿透優化

  • 含義:查詢一個不存在的數據,由於緩存是不命中時需要從資料庫查詢,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到資料庫去查詢

  • 產生原因

    • 業務代碼自身問題

    • 惡意攻擊、爬蟲

  • 發現問題

    • 業務的響應時間,受到惡意攻擊時,普遍請求被打到存儲層,必會引起響應時間提高,可通過監控發現。

    • 業務本身問題

    • 相關指標:總調用數、緩存層命中數、存儲層命中數

###解決方法1:緩存空對象(設置過期時間)

  • 含義:當存儲層查詢不到數據後,往cache層中存儲一個null,後期再被查詢時,可以通過cache返回null。

  • 缺點

    • cache層需要存儲更多的key

    • 緩存層和數據層數據“短期”不一致

  • 示例代碼

public String getPassThrough(String key) {
   String cacheValue = cache.get(key);
   if( StringUtils.isEmpty(cacheValue) ) {
       String storageValue = storage.get(key);
       cache.set(key , storageValue);
       if( StringUtils.isEmpty(storageValue) ) {
           cache.expire(key , 60 * 5 );
      }
       return storageValue;
  } else {
       return cacheValue;
  }
}

###解決方法2:布隆過濾器攔截(適合固定的數據)

  • 將所有可能存在的數據哈希到一個足夠大的bitmap中,一個不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力

 

 

緩存雪崩優化

  • 含義:由於cache伺服器承載大量的請求,當cache服務異常離線,流量直接壓向後端組件,造成級聯故障。或者緩存集中在一段時間內失效,發生大量的緩存穿透

解決方法1:保證緩存高可用性

  • 做到緩存多節點、多機器、甚至多機房。

  • Redis Cluster、Redis Sentinel

  • 做二級緩存

解決方法2:依賴隔離組件為後端限流

  • 使用Hystrix做服務降級

解決方法3:提前演練(壓力測試)

解決方法4:對不同的key隨機設置過期時間

 

 

無底洞問題

  • 問題描述:添加機器時,客戶端的性能不但沒提升,反而下降

  • 問題關鍵點

    • 更多的機器 != 更高的性能

    • 更多的機器 = 數據增長與水平擴展

    • 批量介面需求:一次mget隨著機器增多,網路節點訪問次數更多。網路節點的時間複雜度由O(1) -> O(node)

  • 優化IO的方法

    • 命令本身優化:減少慢查詢命令:keys、hgetall、查詢bigKey併進行優化

    • 減少網路通信次數

      • mget由O(keys),升級為O(node),O(max_slow(node)) , 甚至是O(1)

    • 降低接入成本:例如客戶端長連接/連接池、NIO等

 

 

熱點Key的重建優化

  • 熱點Key(訪問量比較大) + 較長的重建時間(重建過程中的API或者介面比較費時間)

  • 導致的問題:有大量的線程會去查詢數據源並重建緩存,對存儲層造成了巨大的壓力,響應時間會變得很慢

1.三個目標

  • 減少重建緩存的次數

  • 數據儘可能一致

  • 減少潛在危險:例如死鎖、線程池大量被hang住(懸掛)

2.兩種解決方案

 

  • 互斥鎖(分散式鎖)

    • 第一個線程需要重建時候,對這個Key的重建加入分散式鎖,重建完成後進行解鎖

    • 這個方法避免了大量的緩存重建與存儲層的壓力,但是還是會有大量線程的阻塞

    jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)

    String get(String key) {
       String SET_IF_NOT_EXIST = "NX";
       String SET_WITH_EXPIRE_TIME = "PX";
       
       String value = jedis.get(key);
       if( null == value ) {
           String lockKey = "lockKey:" + key;
           if( "OK".equals(jedis.set(lockKey , "1" , SET_IF_NOT_EXIST ,
                         SET_WITH_EXPIRE_TIME , 180)) ) {
               value = db.get(key);
               jedis.set(key , value);
               jedis.delete(lockKey);
          } else {
               Thread.sleep(50);
               get(key);
          }
      }
       return value;
    }
  • 永遠不過期

    • 緩存層面:不設置過期時間(不使用expire)

    • 功能層面:為每個value添加邏輯過期時間,單發現超過邏輯過期時間後,會使用單獨的線程去重建緩存。

    • 還存在一個數據不一致的情況。可以將邏輯過期時間相對實際過期時間相對減小

緩存的受益與成本

1.受益

  • 加速讀寫

    • CPU L1/L2/L3 Cache、瀏覽器緩存、Ehcache緩存資料庫結果

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.拉取Mysql鏡像 docker pull mysql:5.7 2.檢查mysql鏡像 docker inspect mysql:5.7 "Entrypoint": [ "docker-entrypoint.sh" ], 3.本地創建mysql外掛的目錄 ##掛載到容器內/docker-entr ...
  • 資料庫對象 用戶模式:指資料庫用戶所創建和存儲數據對象的統稱。在訪問其它用戶模式的資料庫對象時需加上用戶模式。 如:scott.emp, scott.dept等。 資料庫對象包括:表、視圖、索引、序列、目錄、同義詞、資料庫用戶、存儲過程、函數、觸發器等。 同義詞 同義詞是現有資料庫對象的一個別名。 ...
  • T-SQL常用語句創建資料庫: CREATE DATABASE [資料庫名] CREATE DATABASE [School]刪除資料庫: DROP DATABASE [資料庫名] DROP DATABASE [School]創建表: CREATE TABLE [表名]([列名] [類型](長度) ...
  • MySQL中6種常見的約束:主鍵約束(primary key)、外鍵約束(foreign key)、非空約束(not null)、唯一性約束(unique)、預設值約束(defualt)、自增約束(aoto_increment),下麵是添加、刪除這幾種約束的一些方法。 --我已經建了資料庫; 1 - ...
  • >1 啟動資料庫 在cmd命令視窗,直接輸入"sqlplus",直接進入oracle管理界面,輸入用戶名和密碼後,開始啟動資料庫,啟動資料庫三個步驟:啟動實例、載入資料庫、打開資料庫 命令格式: startup [nomount|mount|open|force][restrict][pfile=f ...
  • 那大數據處理技術怎麼學習呢?首先我們要學習Java語言和Linux操作系統,這兩個是學習大數據的基礎,學習的順序不分前後。 Java:大家都知道Java的方向有JavaSE、JavaEE、JavaME,學習大數據要學習那個方向呢?只需要學習Java的標準版JavaSE就可以了,像Servlet、JS ...
  • `起因:`最近同事在做定時打卡的東西,遇到一個詭異的問題,端只是傳了一個開始時間跟打卡周期,剩下的打卡時間都是由服務端自己生成的,顯示的截止時間有的變成==23:59:59==. 有時候又變成了 ==00:00:00==,沒有找到原因,讓幫忙找一下原因,之前沒有遇到過這種情況,一時來了興趣。 通過編 ...
  • 前面有一篇《在SQL中直接把查詢結果轉換為JSON數據》https://www.cnblogs.com/insus/p/10905566.html,是把table轉換為json。 現反過來,當SQL從前端接收過來的數據是JSON的話,需要把它轉換為TABLE。在MS SQL Server 2016有 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...