Redis學習系列之——高并發應用的緩存問題(二)

一、布隆過濾器

? ? ? ? 布隆過濾器由一個 BitMap 和若干 Hash 函數組成,可以用來快速判斷一個值是否存在后端存儲中。它是解決 Redis 緩存穿透問題的一個不錯的解決方案。

工作原理

步驟1:當 key-value 鍵值對存儲到 Redis 后,向布隆過濾器添加 key

步驟2:布隆過濾器會對 key 進行多個獨立的哈希運算,假設是3個Hash,則得到 hash1、hash2、hash3

步驟3:假設布隆過濾器的 BitMap 長度為 L,那么 BitMap 中的 hash1 % L、hash2 % L、hash3 % L 這三個位會被設置為1

步驟4:若要查詢某個 key 是否存在于 Redis 中,可以先查詢布隆過濾器。布隆過濾器會檢查 hash1 % L、hash2 % L、hash3 % L 這三個位置是否都為1

步驟4.1:若否,則 key 一定不存在于 Redis 中

步驟4.2:若是,由于可能出現 Hash 沖突,因此無法判斷 key 是否存在于 Redis 中

特點

1、布隆過濾器無法刪除數據,若想要刪除只能全量初始化

2、布隆過濾器采用 Bitmap 結構,十分節省空間(假如1億的key,一般需要10億長度的Bitmap,這樣的 Bitmap 只需要 120MB 左右的空間即可)

3、布隆過濾器適用于數據命中率不高、數據相對固定、數據量大的場景。配合“緩存空值”的策略來對抗緩存穿透時,可以大幅減少 Redis 中空值對應的 key 的數量,從而節約 Redis 空間

示例代碼

void init(){// 初始化布隆過濾器, 預計元素10萬, 誤差率 3%,// 根據這兩個參數會計算出底層 bitmap 的大小及 Hash 函數的數量RBloomFilter<String> bloomFilter = redisson.getBloomFilter("bloom1");bloomFilter.tryInit(100000, 0.03);// 將現有 key 全部初始化for(String key : allKeys){bloomFilter.put(key);}
}String get(String key){// 由布隆過濾器判斷是否存在if(!bloomFilter.contains(key)){return "";}// 布隆過濾器不能確定, 嘗試從緩存中獲取String value = cache.get(key);if(value != null){return value;}// 緩存中不存在, 嘗試從數據庫獲取, 并更新緩存value = db.get(key);if(value != null){cache.set(key, value, 600s)} else {// 緩存空值value = "";cache.set(key, value, 30s);}return value;
}void add(String key, String value){// 新增元素時,除了寫入數據庫,還需要將 key 寫入布隆過濾器db.add(key, value);bloomFilter.put(key);
}

二、bigkey 問題

定義

????????bigkey 是指單值類型(string)大小很大,二級數據結構的大小很大或元素過多。

????????一般地,超過 10KB 的 string,或者超過 5000 個元素的 hash/list/set/zset,可以認定為 bigkey。

危害

1、高并發請求大 key 時,容易導致 Redis 阻塞

2、高并發請求大 key 時,容易導致網絡擁塞

3、過期刪除大 key 時,存在阻塞 Redis 的可能性。(Redis 4.0 之后默認采用過期異步刪除,可以一定程度緩解,但是大 key 刪除仍有較大的性能開銷)

產生原因

? ? ? ? 程序設計不當,或對數據規模預估不足。比如:

1、粉絲列表,若沒有精心設計,大 V 的粉絲列表容易成為大 key;

2、為了方便,把關聯的數據全部放到一個 key 中存儲;

優化方法

1、數據分段存儲,比如一個大的 list,分成10個小的 list 存儲

2、如果 bigkey 不可避免,每次請求盡量取出少量數據,比如用 hmget 代替 hgetall

3、使用合適的數據結構,比如一個大的 JSON 存儲為 string 類型,容易成為大 key,使用 hash 可以將數據分攤到多個 field 中。

4、設置 key 的過期時間,避免 Redis 內存不斷膨脹

三、命令使用

1、O(N) 操作注意性能問題

????????對于 hgetall、smembers、zrange 等等 O(N) 操作,要關注 N 的值。有遍歷元素的需求時,可以使用 hscan、sccan、zscan 等代替,這些 scan 命令使用游標進行遍歷,一次只返回有限數量的元素以及下一次 scan 的游標,而不是一次性返回全量數據。

2、通過 rename 禁用 keys、flushall、flushdb 等危險命令

3、合理使用 select

????????Redis 多數據庫的功能比較弱,使用數字區分。多個業務分別使用同一個 Redis 實例的不同數據庫,Redis 實際上還是單線程處理。

4、使用批量操作提高效率

? ? ? ? 原生命令:例如用 mget/mset 代替多次 get/set;非原生命令:使用 pipeline 打包發送多個命令。

? ? ? ? 但也要注意批量操作規模不能太大。

四、客戶端連接池

? ? ? ? 應用程序使用 Redis 連接池,可以避免連接頻繁建立、釋放造成的性能損耗。

????????使用連接池后,由連接池維護若干連接,負責這些連接的建立、保活、銷毀。業務層需要使用連接的時候,從連接池取出直接使用,使用完畢后歸還給連接池。

? ? ? ? 連接池的關鍵參數:

1、maxTotal?最大連接數

????????maxTotal 的估算要考慮多方因素,比如:

? ? ? ? (1)一次“借出連接 -> 執行命令 -> 歸還連接"大約耗時 1ms,那么單個連接的 QPS 就是1000,如果業務要求的 QPS 是 50000,那么至少需要 50 個連接,此時 maxTotal 可以比 50 大一些

? ? ? ? (2)Redis 服務端的最大連接數是 maxClient,則應用節點數量 * maxTotal 不能超過 maxClient

? ? ? ? (3)從性能最優考慮,一般設置為和 maxIdle 相等,可以避免緩存池伸縮帶來性能開銷。如果考慮連接占用

? ? ? ? (4)maxTotal 不是越大越好,設置合理的值可以限制應用程序消耗 Redis 的資源,而且由于 Redis 工作線程為單線程,一個大命令阻塞的發生時,即使 maxTotal 設置再大也沒用

2、maxIdle?最大空閑連接數

????????超出 maxIdle 的連接在被歸還后會被緩慢釋放。

????????從性能最優考慮,一般設置為 maxIdle = maxIdle,可以避免緩存池伸縮帶來性能開銷。如果考慮連接占用問題,maxIdle 一般設為業務預期的最高并發數,maxTotal 再放大一倍。

3、minIdle 最少空閑連接數

????????注意,Redis 連接池是懶加載的,因此應用程序啟動時,可以用的連接數不會直接到達 minIdle,如果應用啟動后會有很多請求過來,那么我們提前執行代碼進行預熱,使得初始的可用連接數到達 minIdle 個。

4、blockWhenExhausted? 連接池沒有空閑連接時,調用方是否等待

5、maxWaitMillis??blockWhenExhausted=true 時,調用方等待的最長時間

6、testOnBorrow? 連接池是否在借出連接時,檢測連接的有效性

7、testOnReturn??連接池是否在歸還連接時,檢測連接的有效性

五、數據清除策略

? ? ? ? 在 Redis 中,maxmemory 參數規定了能夠使用的最大內存。

1、已使用內存 < maxmemory

? ? ? ? 此時,Redis 會對過期數據進行清除,方式如下:

(1)被動刪除:惰性刪除,當一個 key 到期時,Redis 不會立刻刪除。而是當客戶端讀/寫一個已經過期的 key 時,Redis 進行刪除

(2)主動刪除:惰性刪除無法確保冷數據被及時刪除,所以 Redis 會定期主動刪除一批已經過期的 key

2、已使用內存 > maxmemory

? ? ? ? 此時,Redis 會觸發主動清理策略。主動清理策略有 8 種:

(1)針對設置了有效期的 key 進行刪除

? ? ? ? a. volatile-ttl:越早過期的數據越先被刪除

? ? ? ? b. volatile-random:隨機刪除

? ? ? ? c. volatile-lru:使用 LRU 算法刪除

? ? ? ? d. volatile-lfu:使用 LFU 算法刪除

(2)針對所有的 key 進行刪除

? ? ? ? e. allkeys-random:隨機刪除

? ? ? ? f. allkeys-lru:使用 LRU 算法刪除

? ? ? ? g.?allkeys-lfu:使用 LFU 算法刪除

(3)不刪除

? ? ? ? h. noeviction:缺省值。不會刪除任何數據,并拒絕客戶端的所有寫操作。

3、配置建議

(1)Redis 默認不限制 maxmemory。生產環境建議配置,并且不要讓 maxmemory 超過物理內存大小,否則會觸發磁盤 swap 影響性能。

(2)一般推薦使用 volatile-lru;如果熱點數據比較多,則用 volatile-lfu

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/89449.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/89449.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/89449.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Expression 類的靜態方法

public static MethodCallExpression Call(Type type, // 包含目標方法的類型string methodName, // 方法名稱Type[]? typeArguments, // 泛型方法的類型參數&#xff08;非泛型方法為 null&#xff09;params Expression[]? arguments // 方…

[Nagios Core] 事件調度 | 檢查執行 | 插件與進程

第五章&#xff1a;事件調度 歡迎回到Nagios Core&#xff01; 在上一章第四章&#xff1a;配置加載中&#xff0c;我們了解了Nagios如何讀取配置文件以知曉需要監控的對象&#xff0c;比如我們的朋友"Web Server 1"。此時Nagios內存中已構建完整的基礎設施拓撲圖。…

Web3 常用前端庫介紹

一、Web3 前端開發&#xff1a;連接用戶與區塊鏈的橋梁 隨著 Web3 生態的蓬勃發展&#xff0c;前端開發從傳統的頁面渲染進化為區塊鏈交互的核心樞紐。Web3 前端庫作為連接用戶與區塊鏈的橋梁&#xff0c;承擔著錢包集成、合約交互、數據可視化等關鍵功能。本文將系統解析主流 …

cnpm命令報internal/modules/cjs/loader.js:797 throw err; ^ Error: Cannot find

在運行一個項目的時候&#xff0c;需要升級電腦各組件的版本&#xff0c;結果導致cnpm命令無法正常使用&#xff0c;cnpm任何命令都會報如下這個錯&#xff1a;找了半天&#xff0c;發現是由于cnpm與npm的版本不一致導致的&#xff0c;所以需要卸載并重新安裝cnpm&#xff0c;重…

15、鴻蒙Harmony Next開發:創建自定義組件

目錄 自定義組件的基本用法 自定義組件的基本結構 struct Component freezeWhenInactive build()函數 Entry EntryOptions Reusable 成員函數/變量 自定義組件的參數規定 build()函數 自定義組件生命周期 自定義組件的創建和渲染流程 自定義組件重新渲染 自定義…

深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()

文章目錄深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()1. 方法定義comparingByKey()comparingByValue()2. 基本用法2.1 使用comparingByKey()2.2 使用comparingByValue()3. 方法重載版本comparingByKey(Comparator)comparingByValue(Comparator)4. 高級用…

Mac下載mysql

安裝 brew list --versions | grep mysql查看已安裝的mysql版本brew search mysql查看支持的mysql版本brew info mysql查看mysql版本信息brew install mysql進行安裝/opt/homebrew/opt/mysql/bin/mysqld --initialize-insecure --user$(whoami) --basedir$(brew --prefix mysql…

PageHelper使用說明文檔

文章目錄一、簡介二、集成步驟三、使用方法四、注意事項五、高級用法一、簡介 PageHelper 是一個開源的 MyBatis 分頁插件&#xff0c;它可以幫助我們在使用 MyBatis 進行數據庫操作時方便地實現分頁功能。通過簡單的配置和少量的代碼修改&#xff0c;就可以在查詢數據時實現分…

grpo nl2sql qwen3 模型強化學習訓練有效果的成立條件有哪些

在使用GRPO&#xff08;強化學習算法&#xff09;對Qwen3模型在NL2SQL&#xff08;自然語言到SQL轉換&#xff09;任務上進行強化學習&#xff08;RL&#xff09;訓練時&#xff0c;其效果成立的核心條件可歸納為以下幾個關鍵維度&#xff0c;這些條件相互關聯&#xff0c;共同…

面向向量檢索的教育QA建模:九段日本文化研究所日本語學院的Prompt策略分析(6 / 500)

面向向量檢索的教育QA建模&#xff1a;九段日本文化研究所日本語學院的Prompt策略分析&#xff08;6 / 500&#xff09; 系列說明 500 所日本語言學校結構化建模實戰&#xff0c;第 6 篇。每篇拆解 1 所學校在 Prompt-QA 系統中的建模策略&#xff0c;分享工程經驗&#xff0c;…

墨刀原型圖的原理、與UI設計圖的區別及轉換方法詳解-卓伊凡|貝貝

墨刀原型圖的原理、與UI設計圖的區別及轉換方法詳解-卓伊凡|貝貝最近有個設計由于時間比較倉促直接用 原型做的&#xff0c;但是原型做的大家都知道是沒法用的&#xff0c;以下講解原型和ui的區別&#xff0c;其次我們下面有三種方法把墨刀的原型變成UI圖。一、墨刀原型圖的原理…

前端 nodejs vue2 開發環境和微信開發環境 故障終極處理

現象某個vue2舊項目 引入vue-ls 組件等組件&#xff0c;沖突失敗后刪除,導致開發環境 vxe-table加載失敗&#xff0c;還原后還是不行。前段項目崩潰。報警sass 某個方法 Deprecated &#xff0c;之前不會處理方式_失敗回退代碼項目代碼 刪除 node_modules&#xff0c; 刪除 …

【后端】.NET Core API框架搭建(9) --配置使用Log4Net日志

目錄 1.添加包 2.新建公用類 3.新建配置 4.注冊 4.1.類庫項目設置 5.使用 在 .NET Core 項目中使用 Log4Net 做日志記錄&#xff0c;具有很多優勢。盡管 .NET Core 自帶了 ILogger 接口&#xff08;如使用內置的 ConsoleLogger、DebugLogger 等&#xff09;&#xff0c;但…

Agent交互細節

本文參考了https://www.bilibili.com/video/BV1v9V5zSEHA/視頻及原作者代碼實踐 本文主要實踐在第3節1、MCP MCP官方地址&#xff1a;https://modelcontextprotocol.io/introduction MCP 是一個開放協議&#xff0c;它規范了應用程序向 LLM 提供上下文的方式。 架構&#xff1a…

AI+醫療!VR和MR解剖學和針灸平臺,智能時代如何重塑健康未來

在智能時代&#xff0c;“AI醫療”正從精準診斷入手&#xff0c;推動醫療系統變革&#xff0c;通過個性化健康管理、智能診療輔助等方式重塑健康未來&#xff01;將人工智能&#xff08;AI&#xff09;與虛擬實境&#xff08;VR&#xff09;應用到中醫教學&#xff0c;透過該系…

Sersync和Rsync部署

學習參考連接 以下是我在學習過程中借鑒的經驗和下載資源鏈接&#xff0c;感謝幾位大佬的幫助&#xff0c;也供各位參考。 Rsync踩坑&#xff1a; https://blog.csdn.net/XiaoXiaoYunXing/article/details/120160395 Sersync下載源 http://down.whsir.com/downloads/sersy…

Django基礎(四)———模板常用過濾器

前言上篇文章給大家介紹了DTL模板的部分知識點這篇文章繼續帶大家深入理解Django框架中的模板過濾器一、模板常用過濾器1.add將傳進來的參數添加到原來的值上面。這個過濾器會嘗試將值和 參數轉換成整形然后進行相加。如果轉換成整形過程中失敗了&#xff0c;那么會將值和參數進…

國內MCP服務器搜索引擎有哪些?MCP導航站平臺推薦

在人工智能技術蓬勃發展的今天&#xff0c;AI模型與外部工具和服務的交互能力正成為推動技術進步的關鍵。AIbase&#xff08;<https://mcp.aibase.cn/>&#xff09;作為一個專注于MCP(Model Context Protocol&#xff0c;模型上下文協議)服務器的集合平臺&#xff0c;為全…

Python中with的作用和用法

在這里我們來詳細解釋一下Python中非常重要的 with 語句。 我會從 “為什么需要它” 開始&#xff0c;然后講解 “它是什么以及如何使用”&#xff0c;最后深入到 “它的工作原理” 和 “如何自定義”。1. 為什么需要 with 語句&#xff1f;(The Problem) 在編程中&#xff0c;…

緩存雪崩、緩存穿透,緩存擊穿

Redis是一個完全開源免費的高性能非關系型&#xff08;NOSQL&#xff09;的key-value數據庫。 Redis不可能把所有的數據都緩存起來(內存昂貴且有限)&#xff0c;所以Redis需要對數據 設置過期時間&#xff0c;并采用的是惰性刪除定期刪除兩種策略對過期鍵刪除。Redis對過期鍵的…