💫《博主主頁》:
🔎 CSDN主頁__奈斯DB
🔎 IF Club社區主頁__奈斯、
🔥《擅長領域》:擅長阿里云AnalyticDB for MySQL(分布式數據倉庫)、Oracle、MySQL、Linux、prometheus監控;并對SQLserver、NoSQL(Redis)有了解
💖如果覺得文章對你有所幫助,歡迎點贊收藏加關注💖
????作為DBA或運維在日常與Redis打交道時,往往更關注部署安裝🔧、Key清理🧹、內存回收💾、備份恢復🔄等這些運維層面的問題,也就是非業務相關的問題。但大家否深入思考過:
?為什么現代數據庫架構中需要引入Redis做緩存?
?不同的NoSQL在緩存場景下各有怎樣的特性?
?當高并發來臨時,緩存穿透、擊穿、雪崩這些問題究竟會對系統造成什么影響?
????博主在此之前也沒有考慮過這些問題(應該大部分DBA或者運維都沒有考慮過這些問題,因為引用緩存技術,以及緩存策略(穿透/擊穿/雪崩的防治)通常被視為研發的職責范疇)
,因為DBA或者運維更多的是關心NoSQL本身的穩定性保障,直到親身經歷了一次高并發場景下的緩存雪崩事故,才意識到意識到這些業務邏輯對運維人的重要性。
????那么今天這篇文章就從業務角度出發,一起來了解和學習一下互聯網數據庫架構演進中Redis緩存的技術必然性,以及其他NoSQL在緩存場景下的特點比較,并在高并發場景下緩存穿透、緩存擊穿、緩存雪崩的體系化解決方案。
????寫這篇文章的初衷是想讓不懂為什么加緩存技術的小伙伴們明白,此篇文章的內容來源于B站UP主“遇見狂神說”中的前部分視頻講解內容,博主在文章中對內容稍加潤色,并對流程圖重新構圖加以個人理解。那么正好也借此機會推薦給大家這個Redis好課,在B站上搜索“遇見狂神說”UP主,就可以搜索到他講的Redis課程,UP主是個大佬,Redis講的非常通透,最最最主要的是UP主是無償且免費的把Redis這套課程分享出來的(免費!香!)
,并且視頻中的相關講解UP主也愿意讓學習過的小伙伴進行整理和分享,免費是情誼,收費是本分,感謝大佬為愛發電💞,為我們帶來了如此寶貴的學習資源。
目錄
- Redis介紹
- NoSQL分類
- 一、緩存穿透(Cache Penetration)
- 二、緩存擊穿(Cache Breakdown)
- 三、緩存雪崩(Cache Avalanche)
???
20世紀90年代:數據庫的單機時代:
????在互聯網發展初期,網站訪問量普遍較小,許多網站仍以靜態HTML頁面為主。由于用戶請求量有限,應用服務器和數據庫服務器的負載壓力并不大。因此,單臺關系型數據庫(如MySQL)足以滿足數據存儲和查詢的需求。這一階段的架構簡單直接,甚至數據庫服務和應用部署在同一臺機器上,無需復雜的分布式設計或性能優化。
????那么這一時期的Web應用主要呈現以下特點:
- 靜態內容占絕對主導,動態請求占比很低
- 單臺MySQL數據庫完全能夠滿足存儲和查詢需求
- 應用服務器和數據庫服務器都承受著極小的壓力
????此時的典型架構如下:
架構圖說明 Web服務器:
- 請求分發中心
- 接收所有HTTP請求(GET/POST)
- 區分靜態請求(.html/.jpg)和動態請求(.php/.asp)
- 靜態請求直接返回文件,動態請求轉發給后端處理
- 基礎服務支撐
- 單進程/單線程模型(早期Apache的prefork模式)
- 不支持keep-alive(每個請求新建TCP連接)
- 典型配置:Pentium 100MHz CPU + 32MB內存
???
???MySQL 數據庫層:
- 數據庫用于持久化存儲應用的核心數據,例如用戶、訂單、商品等結構化數據。
- 數據庫層需要處理事務、并發訪問、數據一致性等問題。
- 數據庫也提供了 ACID 特性,保證數據的可靠性和完整性。
???
21世紀00年代,大數據時代:
????隨著互聯網的發展和數據量的不斷增長,傳統單臺數據庫在處理海量數據時逐漸暴露出性能瓶頸。以下是一些常見的問題:
- 存儲瓶頸: 隨著數據的激增,單臺服務器的磁盤空間逐漸不足。單一磁盤和服務器無法滿足日益增長的數據存儲需求。
- 單表數據量過大: 例如,當一張表的數據量達到幾百萬條時,查詢操作將會消耗大量內存,導致性能下降,且在沒有合理優化的情況下,查詢速度會急劇下降。
- 高并發訪問: 隨著訪問量增加,單臺數據庫服務器可能無法承受來自多個用戶的并發請求。每秒鐘的查詢次數(QPS)會造成數據庫的負載過重,導致響應時間延遲。
- 查詢效率低: 當大量用戶頻繁查詢相同的數據時,數據庫不斷重復執行相同的查詢操作,使得查詢效率下降,嚴重時可能會導致數據庫崩潰。
- …
????在大數據和高并發的背景下,提升查詢效率成為了一個至關重要的課題。傳統的數據庫雖然是存儲數據的核心技術,但隨著數據量的增加,單臺數據庫在高并發場景下的響應時間會急劇上升,甚至導致系統性能瓶頸。為了應對這些挑戰,技術進步經歷了幾個階段,從最初的數據庫結構和索引優化,到文件緩存和磁盤I/O優化,再到如今的緩存技術,特別是Redis等內存緩存技術的應用。
????首先,數據庫通過優化表結構和索引
來提升查詢效率。這些優化可以減少掃描全表的操作,快速定位所需數據,進而提升查詢速度。然而,隨著數據量的劇增,這種優化方式逐漸顯得力不從心,尤其是在面對高并發請求時,數據庫的負載急劇增加,查詢性能出現瓶頸。
????隨著技術的發展,文件緩存和磁盤I/O優化
成為了重要的提升手段。特別是SSD(固態硬盤)的普及,使得磁盤I/O性能得到了顯著提升。文件緩存通過將部分數據存儲在磁盤上,以減少數據庫的頻繁讀寫,從而減輕數據庫的壓力。然而,磁盤I/O的速度畢竟不如內存,因此,文件緩存雖然有效,但也有限。
????既然磁盤I/O的速度畢竟不如內存,那么能不能將數據庫中的數據緩存到內存中用來提高查詢效率呢?答案是當然可以,舉一個例子💫,在一般情況下網站80%的情況都是在讀,高并發的去查詢單臺數據庫的話就會增加查詢響應時間,比如張三查詢了1號商品,李四也同樣去查詢了一樣的1號商品,都是同樣的查詢操作,每次都要去查詢數據庫的話讓壓力本來就很大的數據庫更加雪上加霜,因此能不能讓多次不變的1號商品做成緩存,讓李四或者其他同樣想查詢1號商品的用戶直接可以在緩存中調用1號商品,而避免再次在數據庫中查詢呢?為了解決這一問題,緩存技術孕育而生,緩存技術是解決上述問題的關鍵技術之一。
????那么,緩存技術的核心目標是:減少對數據庫的訪問,避免頻繁執行重復的查詢操作
。緩存通過將熱點數據保存在內存中,首先檢查緩存中是否有該數據,若有,則直接從緩存中讀取,避免了對數據庫的多次查詢。這不僅提升了響應速度,還顯著降低了數據庫的壓力,尤其在高并發的場景下,緩存能夠有效減輕數據庫的負擔,提升系統的整體性能。
????其中,Redis作為一種高效的內存鍵值數據庫
,成為了最常用的緩存解決方案。它以其超低的延遲和高效的讀寫性能,尤其適用于需要處理大量并發請求的應用場景。例如,電商平臺、社交媒體等高訪問量的應用,通過將熱點數據存儲在Redis緩存中,避免頻繁訪問數據庫,從而提升系統性能。緩存不僅減少了數據庫的壓力,還改善了用戶的體驗,尤其是在響應速度上。
那么總結一下緩存的作用:
- 提高查詢效率: 緩存將高頻訪問的數據存儲在內存中,避免每次都去查詢數據庫,極大地提高了響應速度。
- 減少數據庫負載: 通過緩存,數據庫的查詢壓力得以減少,尤其是在高并發的情況下,緩存能夠有效地減輕數據庫的負擔。
- 提升用戶體驗: 減少查詢延遲,提升用戶對系統的響應速度和體驗。
???在總結一下緩存的工作原理:
????緩存將數據存儲在快速訪問的存儲介質(如內存)中,每當用戶發起查詢時,系統首先檢查緩存中是否有該數據。如果數據存在,就直接從緩存中讀取,避免了對數據庫的多次訪問。這種機制不僅加快了查詢速度,也大幅降低了數據庫的壓力。
????不過,緩存技術并不是萬能的,它主要用于加速對高頻訪問數據的讀取,而對于大多數長期存儲的數據,傳統的關系型數據庫依然不可替代。
因此,緩存技術往往與數據庫的讀寫分離技術結合使用,以進一步優化系統性能。通過ProxySQL等工具,可以實現數據庫的讀寫分離,將寫操作集中在主數據庫上,而將讀操作分散到多個從數據庫上,這樣可以有效提高系統的并發處理能力。
????從最初的數據庫結構優化,再到文件緩存和磁盤I/O優化,再到緩存技術與傳統關系型數據庫的結合(發展過程:優化數據結構和索引---->文件緩存(磁盤IO性能的提升,比如SSD全閃盤)---->然后才到緩存技術,也就是NoSQL)
,整個技術演變使得高并發場景下的性能瓶頸得到了有效解決。Redis與傳統關系型數據庫的結合(NoSQL+RDBMS技術)
,形成了一個高效的協作機制:Redis負責緩存高頻訪問的數據,而數據庫則存儲長期數據。兩者協同工作,使得系統能夠在面對大量請求時保持高效運行。
架構圖說明 Redis 緩存層:緩存層不僅僅可以是Redis,也可以是Memcached(緩存,內存數據庫)。不僅僅NoSQL數據庫可以做緩存,其實只要帶有緩存技術的都可以在緩存層。
- 緩存存儲:Redis 用于存儲高頻查詢的數據,例如用戶信息、熱門商品、常見查詢結果等。
- 緩存策略:采用合適的緩存過期策略(TTL,Time-To-Live)來確保緩存數據不會過期。可以使用 LRU(Least Recently Used) 策略來避免緩存溢出。
- 異步更新:通常,緩存的數據會有一定的過期時間,過期后緩存失效。數據庫中的數據變化時,可以觸發緩存的更新(例如,更新操作后刪除對應的緩存)。
???
???MySQL 數據庫層:
- 數據庫用于持久化存儲應用的核心數據,例如用戶、訂單、商品等結構化數據。
- 數據庫層需要處理事務、并發訪問、數據一致性等問題。
- 數據庫也提供了 ACID 特性,保證數據的可靠性和完整性。
???
21世紀10年代:多元數據時代
????在2010至2020年間,世界經歷了巨大的變化,尤其是在信息技術和互聯網的飛速發展下,出現了許多以前未曾存在的數據類型。例如,互聯網中的地圖定位信息、音樂視頻信息、新聞熱榜信息等,這些信息不再僅僅是文本數據
,而是變得更加多元化,涵蓋了圖片、音頻、視頻、地理位置等多種數據形式。
????隨著這些多元數據的涌現,傳統的關系型數據庫,尤其是MySQL,在存儲大文件、圖片等信息時面臨著巨大的挑戰。特別是在查詢時,MySQL的效率顯著降低,數據庫的壓力急劇上升。原因在于,單一的MySQL數據庫已無法滿足存儲這些復雜、多元化數據的需求。因此,必須研發新的數據庫類型來應對這些變化。例如,專門用于存儲定位信息的數據庫、用于存儲大文件的數據庫,或是圖數據庫,專門用于存儲圖片等數據。
????此外,隨著互聯網的普及,用戶的個人信息、社交網絡、地理位置、音樂視頻、以及用戶自己產生的數據(如日志等)都在爆發式增長。與傳統的行列數據存儲方式不同,這些數據往往呈現出無序、動態變化的特點。例如,社交網絡和地理位置數據是一個動態發展的圖譜,新聞熱榜則需要實時更新。這些數據不適合傳統的關系型數據庫,以表格中的行或列來存儲。
????為了解決這些問題,技術發展引入了NoSQL技術,提供了更加靈活和高效的方式來處理這類動態、無序的數據。NoSQL數據庫能夠更好地適應這些數據的存儲需求,其橫向擴展性使得存儲和處理這些數據變得更加可行。
架構圖說明 API網關:
???統一接入層,負責協議轉換、限流鑒權等,典型技術:Kong/Nginx
???
???統一數據服務層UDSL:
???Unified Data Service Layer, UDSL,是一種用于整合和管理企業內部各種數據源的中間層
???
???數據存儲層(核心組件):
- MySQL集群:
- 分庫分表:用戶訂單按user_id哈希分片
- GTID復制:全局事務標識保證主從一致性
- 典型場景:銀行交易、庫存管理等ACID場景
- MongoDB分片集群:
- 自動分片:基于shard key自動平衡數據
- 文檔版本控制:MVCC并發控制
- 典型場景:CMS系統、產品目錄
- Neo4j集群:
- 原生圖存儲:免索引鄰接設計
- Cypher查詢:聲明式圖查詢語言
- 典型場景:社交關系、推薦系統
- InfluxDB集群:
- 時間分片:按時間范圍自動分區
- 連續查詢:實時聚合時序數據
- 典型場景:IoT設備監控、應用指標
- Redis生態圈:
- RedisJSON:支持JSON文檔操作
- RedisGraph:圖數據庫功能
- 典型場景:會話緩存、實時排行榜
???
???數據湖:
- 數據集成:通過各數據庫的變更捕獲機制(如MySQL binlog)集中原始數據
- 典型技術:Apache Kafka + Delta Lake
- 用途:離線分析、機器學習訓練
???
???
???
Redis介紹
????Redis(Remote Dictionary Server,即遠程字典服務),簡稱Redis。是一個開源的使用ANSI C語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API, 并且免費和開源!
????redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎上實現了master-slave(主從)同步。
????Redis 是一個高性能的key-value數據庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合可以對關系數據庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。
????Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹復制。存盤可以有意無意的對數據進行寫操作。由于完全實現了發布/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道并接收主服務器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗余很有幫助。
????redis的官網地址,非常好記,是redis.io。(域名后綴io屬于國家域名,是british Indian Ocean territory,即英屬印度洋領地),Vmware在資助著redis項目的開發和維護。
????從2010年3月15日起,Redis的開發工作由VMware主持。從2013年5月開始,Redis的開發由Pivotal贊助。
????并且Redis推薦在Linux上搭建,不推薦在windows上搭建。
Redis性能方面的表現:
????下面是官方的bench-mark數據:
????????????測試完成了50個并發執行100000個請求。
????????????設置和獲取的值是一個256字節字符串。
????????????Linux box是運行Linux 2.6,這是X3320 Xeon 2.5 ghz。
????????????文本執行使用loopback接口(127.0.0.1)。
????結果: 讀的速度是110000次/s,寫的速度是81000次/s。
???
???
Redis的特性:
特性 描述 內存存儲 Redis 是內存數據庫,所有數據存儲在內存中,提供非常高的讀寫性能。 數據結構豐富 支持多種數據結構:String、List、Set、Sorted Set、Hash、Bitmap、HyperLogLog、Geospatial。 高性能 提供低延遲(微秒級別)和高吞吐量,適合高并發、高吞吐量應用場景。 持久化機制 提供 RDB 快照和 AOF 日志持久化方式,確保數據持久性。可配置混合持久化模式。 高可用性 通過 Redis Sentinel 提供自動故障轉移和高可用性。 分布式支持 支持 Redis Cluster,提供自動分片和水平擴展。 事務支持 支持事務,通過 MULTI、EXEC、WATCH實現命令的原子執行。 Lua 腳本支持 支持在服務器端執行 Lua 腳本,實現原子操作,減少客戶端與服務器的交互。 發布/訂閱模式 支持 Pub/Sub 模式,允許客戶端訂閱頻道并實時接收消息。 輕量級和易部署 Redis 非常輕量,易于啟動和部署,支持單機及分布式部署。 內存管理策略 提供 LRU、LFU 等內存淘汰策略,確保有效利用內存資源。 強一致性保證 Redis 提供強一致性,支持復制和故障轉移機制。 客戶端支持 支持多種編程語言的客戶端,包括 Java、Python、Go、Node.js、C、C++、PHP、Ruby 等。 應用場景廣泛 用于緩存、消息隊列、排行榜、實時數據分析、會話存儲等多種場景。
???
NoSQL分類
什么是NoSQL:
????NoSQL = Not only SQL(不僅僅是SQL),泛指非關系型數據庫。也就是存儲新時代中的多元化數據。比如專門儲存定位信息的數據庫,專門存儲大文件的數據庫,專門存儲圖片的圖關系數據庫,等等等。
???
???NoSQL的特點:
- 方便擴展,數據之間沒有關系,不需要過多的操作就可以橫向擴展。
- 大數據量高性能。官方測試Redis一秒寫8萬次,讀取11萬次。NoSQL的緩存記錄級是一種細粒度的緩存,性能會比較高
- 數據類型是多樣型的。對于關系型數據庫需要事先設計數據的表結構(現實中很少有人可以通過三大范式把數據庫設計的很好),對于NoSQL而言不需要事先設計數據庫,隨取隨用。
???
???RDBMS關系型數據庫和NoSQL非關系型數據庫的區別:
關系型數據庫 非關系型數據庫 結構化數據 不僅僅是數據。非結構化數據,多元化數據結構 有特定的SQL語句 沒有固定的查詢語句 數據和關系都存在單獨的表中(row行、column列) 鍵值對存儲,列存儲,文檔存儲,圖形數據庫(社交關系) 數據定義語言(DML、DDL、DQL、DCL、TCL) 嚴格的一致性(遵循ACID特性) 最終一致性 基礎的事務 CAP定理和BASE(異地多活、) 高性能、高可用、高擴展性 高性能、高可用、高擴展性 … … ???
???
NoSQL的四大分類:
- 內存鍵值存儲(Key-value stores):redis、memcached、Tair、Voldemort、Oracle BDB
- 文檔存儲(Document stores):mongoDB、conthDB
- 列存儲數據庫:Redshift、BigQuery、Snowflake、HBase、分布式文件系統。注意:關系型數據庫大多以行存儲
- 圖關系數據庫(Graph DBMS):Neo4j、infoGrdid、Infinite Graph。注意:圖關系數據庫存的不是圖形,而是存放圖關系的。比如:朋友圈社交網絡、廣告推薦等
分類 舉例 典型應用場景 數據模型 優點 缺點 內存鍵值存儲(Key-value stores) redis、memcached、Tair、Voldemort、Oracle BDB 內容緩存,主要用于處理大量數據的高訪問負載,也用于一些日志系統等等。 Key 指向Value 的鍵值對,通常用hash table來實現。 查找速度快 數據無結構化,通常只被當作字符串或者二進制數據 文檔存儲(Document stores) mongoDB、conthDB Web應用(與Key-Value類似,Value是結構化的,不同的是數據庫能夠了解Value的內容) Key-Value對應的鍵值對,Value為結構化數據 數據結構要求不嚴格,表結構可變,不需要像關系型數據庫一樣需要預先定義表結構 查詢性能不高,而且缺乏統一的查詢語法。 列存儲數據庫 Redshift、BigQuery、Snowflake、HBase、分布式文件系統 分布式的文件系統 以列簇式存儲,將同一列數據存在一起 查找速度快,可擴展性強,更容易進行分布式擴展 功能相對局限 圖關系數據庫(Graph DBMS) Neo4J、InfoGrid、Infinite Graph 社交網絡、推薦系統等。專注于構建關系圖譜 圖結構 利用圖結構相關算法。比如最短路徑尋址,N度關系查找等 很多時候需要對整個圖做計算才能得出需要的信息,而且這種結構不太好做分布式的集群方案
???
????互聯網架構演變 + Redis初探 + NoSQL分類介紹的講解到這里就算完成了!相信看完的小伙伴們對緩存技術的理解已經煥然一新了?。不過一個人的精力畢竟是有限的🕶?,文章中可能有些細節沒覆蓋全面,歡迎各位大佬評論區拍磚補充 💬,提出改進意見。
????各位看官可以休息一下,摸魚10分鐘🕒…
????下一站高能預警 🚨: 直擊高并發三大緩存問題——
🔥 緩存穿透(請求像穿了隱身衣👻)
💥 緩存擊穿(熱點數據突然暴斃💣)
?? 緩存雪崩(集體去世的慘案🏔?)
???
一、緩存穿透(Cache Penetration)
理解緩存穿透:
????緩存穿透是指查詢一個在數據庫中肯定不存在的數據。為了避免每次請求都直接訪問數據庫,我們通常會使用緩存來提高查詢效率。
????正常的緩存使用流程大致如下:
- 查詢緩存:首先,會檢查緩存中是否存在需要的數據。如果緩存中有數據,就直接返回,不需要訪問數據庫。
- 緩存失效或不存在數據:如果緩存中沒有數據,或者緩存的數據已經過期,那么系統會訪問數據庫去查找數據。
- 查詢結果為空:如果數據庫中查詢到的數據為空(即數據確實不存在),那么我們不會把這個空結果存入緩存。
????舉個例子,比如我傳一個用戶 id 為 -1,這個用戶 id 在緩存里面是肯定不存在的,所以會去數據庫里面查詢,如果有搞事情的人,大批量請求并傳用戶 id 為 -1,那就和沒用 redis 一樣,導致數據庫壓力過大而崩潰。
????總結來說,緩存穿透問題就是指我們查詢的那個數據本來就不存在,而這種查詢沒有被有效地攔截,導致每次都要訪問數據庫,造成緩存的無效使用。
???
???
解決方法:
- 接口層增加校驗:不合法的參數直接返回(如ID格式、范圍限制)。不相信任務調用方,根據自己提供的 API 接口規范來,作為被調用方,要考慮可能任何的參數傳值。
- 緩存空值:在緩存查不到,DB 中也沒有的情況,可以將對應的 key 的 value 寫為 null,或者其他特殊值寫入緩存,同時將過期失效時間設置短一點(如30秒),以免影響正常情況。這樣是可以防止反復用同一個 ID 來暴力攻擊。
if (data == null) {cache.set(key, null, 30); // 緩存空值 }
- 網關設置閾值:正常用戶是不會這樣暴力功擊,只有是惡意者才會這樣做,可以在網關 NG 作一個配置項,為每一個 IP 設置訪問閾值。
- 布隆過濾器:高級用戶布隆過濾器(Bloom Filter), 這個也能很好地防止緩存穿透。原理就是利用高效的數據結構和算法快速判斷出你這個 Key 是否在 DB 中存在,不存在你 return 就好了,存在你就去查了 DB 刷新 KV 再 return。
???
二、緩存擊穿(Cache Breakdown)
理解緩存擊穿:
????緩存擊穿是指某個緩存中的熱點數據(即頻繁訪問的數據)在短時間內失效,導致大量并發請求繞過緩存,直接訪問數據庫。這種情況就像是屏障上的一個洞,導致數據查詢瞬間變得非常慢。
????具體來說,當一個非常熱門的緩存數據失效時,如果沒有其他機制來保護,所有的并發請求都會直接去訪問數據庫,給數據庫帶來巨大的壓力。這樣,原本應該由緩存處理的請求就會集中到數據庫,造成性能瓶頸,甚至可能導致數據庫崩潰。
????舉個例子,好比秒殺某一個商品或者某個top實時熱搜,這個key一直在緩存中,但緩存是有過期時間的,假如這個key是1800秒(30分鐘)過期,1800秒后這個key還是非常熱點,但key過期了,那么會直接在數據庫中進行查詢,查詢到后放入緩存中,在放入緩存這段過程,雖然時間很短很短,比如只有0.1秒,但就是這0.1秒會直接讓數據庫并發激增,甚至導致宕機。
???
???
解決方法:
- 互斥鎖:在緩存失效時,為獲取數據的請求加鎖(如Redis的SETNX),確保只有一個請求去查詢數據庫并更新緩存,其他請求等待獲取緩存更新后的結果。
String value = cache.get(key); if (value == null) {if (lock.tryLock()) { // 獲取分布式鎖try {value = db.get(key); // 查數據庫cache.set(key, value);} finally {lock.unlock();}} }
- 提前更新緩存:在數據更新時,提前刷新相關緩存,以避免緩存失效。
- 熱點數據永不過期(慎用):對極熱點數據不設過期時間,通過后臺任務定期更新,充分把 Redis 高吞吐量性能利用起來。
- 邏輯過期:不設置物理過期時間,而是在value中存儲過期時間。業務邏輯判斷是否過期,異步更新緩存。
???
三、緩存雪崩(Cache Avalanche)
理解緩存雪崩:
????緩存雪崩是指在同一時間,大量緩存數據同時失效,導致大量請求直接訪問數據庫。這樣會給數據庫帶來極大壓力,甚至可能導致數據庫崩潰。
????舉個例子,雙十一期間,凌晨12點會迎來搶購高峰期,熱點商品都會放在緩存中,假設緩存1小時,那么到凌晨1點這批熱點數據就會批量過期,那么就會導致大量的商品直接在數據庫中進行查詢,直接讓數據庫并發激增,導致宕機。
????還有就是緩存數據庫異常宕機,大量緩存同時失效,導致所有請求涌向數據庫。
???
???
解決方案:
- 分散過期時間:為緩存key設置分散的過期時間(如基礎時間+隨機偏移量),避免同一時間大量緩存同時失效。
cache.set(key, value, baseTime + random.nextInt(300)); // 基礎時間+隨機秒數
- 提前預熱緩存:在系統負載較低時,提前加載重要的數據到緩存中。
- 使用多級緩存:采用多層級緩存(如本地緩存+Redis),避免單點故障。
- 高可用架構:Redis集群部署(主從+哨兵/Cluster模式),避免全盤崩潰。
- 接口限流:當訪問的不是核心數據的時候,在查詢的方法上加上接口限流保護。
???
總結一下:
- 緩存穿透: 查詢一個 不存在的數據,緩存和數據庫都沒有,導致每次請求都直接訪問數據庫(如惡意請求不存在的ID)。
- 緩存擊穿: 某個 熱點key過期 時,大量并發請求同時穿透緩存,直接訪問數據庫。
- 緩存雪崩: 大量緩存key同時失效或緩存服務宕機,導致所有請求涌向數據庫。
問題 觸發條件 核心解決方案 緩存穿透 查詢不存在的數據(如惡意請求不存在的ID)。 1、接口層增加校驗
2、緩存空值
3、網關設置閾值
4、布隆過濾器緩存擊穿 熱點key突然失效 1、互斥鎖
2、提前更新緩存
3、熱點數據永不過期(慎用)
4、邏輯過期緩存雪崩 大量key同時失效/服務宕機 1、分散過期時間
2、提前預熱緩存
3、使用多級緩存
4、高可用架構
5、接口限流
????呼,關于這篇的內容到這里就結束啦!🎉 尤其是文章中的6個示意圖,花了接近4小時精心繪制?,就是希望能更直觀地展現原理,讓枯燥的文字變得生動易懂💡。看在博主爆肝作圖、瘋狂掉發的份上😝,各位大佬賞個三連吧👍?💬!也讓博主有更多的動力去認真撰寫后續的博客~🚀