緩存雪崩、擊穿、穿透及解決方案_保證緩存和數據庫一致性

文章目錄

  • 緩存雪崩、擊穿、穿透
    • 1.緩存雪崩
      • 造成緩存雪崩
        • 解決緩存雪崩
    • 2. 緩存擊穿
      • 造成緩存擊穿
      • 解決緩存擊穿
    • 3.緩存穿透
      • 造成緩存穿透
      • 解決緩存穿透
  • 更新數據時,如何保證數據庫和緩存的一致性?
    • 1. 先更新數據庫?先更新緩存?
      • 解決方案
    • 2. Cache Aside策略
      • ① 先更新數據庫,再刪除緩存
        • 保證更新數據庫、刪除緩存都執行成功
      • ② 先刪除緩存,再更新數據庫
        • 解決方案

在這里插入圖片描述

緩存雪崩、擊穿、穿透

一般用戶數據存儲于磁盤,讀寫速度慢。

使用redis作為緩存,相當于數據緩存在內存,大大提高系統性能

redis作為緩存,就會有緩存異常的三個問題

1.緩存雪崩

在這里插入圖片描述

緩存都設置了過期時間

造成緩存雪崩

  • 大量緩存數據在同一時間過期

  • redis故障宕機

    若此時有大量用戶請求,無法在redis處理,都直接訪問數據庫 => 數據庫壓力驟增(嚴重造成數據庫宕機) => 形成一系列連鎖反應 => 整個系統崩潰

解決緩存雪崩

=> 大量緩存數據在同一時間過期時:

  1. 均勻設置過期時間(對緩存數據的過期時間加上隨機數,保證數據不會在同一時間過期)

  2. 互斥鎖(當業務線程在處理用戶請求時,如果發現訪問的數據不在redis里,加互斥鎖,保證同一時間內只有一個請求來構建緩存(從數據庫讀取數據,再將數據更新到redis),當緩存構建完成后,再釋放鎖。)
    注:互斥鎖設置超時時間,否則若出現請求發生意外阻塞,導致其他請求也一直拿不到鎖

  3. 后臺更新緩存(讓緩存“永久有效”,將更新緩存的工作交由后臺線程定時更新)
    當系統內存緊張時,有些緩存數據被“淘汰”,在“淘汰”和下次更新時間內,業務線程讀取失敗就以為是數據丟失,解決方法:

    1. 后臺線程負責定時更新緩存,同時頻繁地檢測緩存是否失效,若失效,可進行構建緩存

      ? 檢測時間間隔不能太長,太長導致用戶獲取的數據是空值而不是真正的數據,檢測時間間隔最好是毫秒級,用戶體驗一般

    2. 業務線程發現緩存數據失效后,通過消息隊列發送一條消息通知后臺線程更新緩存。后臺線程收到消息后,更新前判斷緩存是否存在,不存在則進行構建緩存。

      ? 緩存更新及時,用戶體驗好

    **注:**后臺更新緩存機制適合進行緩存預熱(業務剛上線時,提前緩存數據,不是等待用戶訪問才來觸發緩存構建)

=> Redis故障宕機時:

  1. 服務熔斷或請求限流機制

    ? 服務熔斷:暫停業務應用對緩存服務的訪問,直接返回錯誤,不再繼續訪問數據庫,直到redis恢復正常。

    ? 請求限流機制:只將少部分請求發送到數據庫進行處理,再多的請求就在入口直接拒絕服務,等到Redis恢復正常 并把緩存預熱完后。

  2. 構建redis緩存高可靠集群

    ? 通過主從節點的方式構建,若redis緩存的主節點宕機,從節點可以切換成為主節點,繼續提供緩存服務

2. 緩存擊穿

造成緩存擊穿

被頻繁訪問的熱點數據過期,此時大量的請求訪問該熱點數據,直接訪問數據庫,數據庫很容易被高并發的請求沖垮

緩存擊穿可以認為是緩存雪崩的一個子集(對應于大量緩存數據在同一時間過期)

解決緩存擊穿

  1. 互斥鎖
  2. 不給熱點數據設置過期時間,由后臺異步更新緩存 / 在熱點數據準備過期前,提前通知后臺線程更新緩存以及重新設置過期時間

3.緩存穿透

對于緩存雪崩、擊穿,數據仍然在數據庫,一旦緩存恢復相應的數據,就可以減輕數據庫的壓力

而對于緩存穿透:

? 用戶訪問的數據,既不在緩存中,也不在數據庫中,導致請求在訪問緩存時,發現緩存缺失,再去訪問數據庫,發現數據庫也沒有要訪問的數據,沒辦法構建緩存來服務后續請求。當有大量的這樣的請求時,數據庫的壓力驟增

造成緩存穿透

  • 業務誤操作,緩存中數據和數據庫數據都被誤刪除
  • 黑客惡意攻擊,故意大量訪問某些讀取不存在數據的業務

解決緩存穿透

  1. 非法請求的限制

    判斷請求參數是否含有非法值?請求字段是否存在?

  2. 緩存空值或默認值

    當線上業務發現緩存穿透時,針對查詢的數據,在緩存中設置一個空值或默認值,后續請求可以從緩存中讀取到數據,而不會繼續查詢數據庫

  3. 使用布隆過濾器快速判斷數據是否存在,避免通過查詢數據庫來判斷數據是否存在。

    寫入數據庫數據時,使用布隆過濾器做標記,當業務線程確認緩存失效后,可以通過查詢布隆過濾器判斷數據是否存在。(大量請求只會查詢布隆過濾器和redis,而不會查詢數據庫)

注:布隆過濾器的實現

在這里插入圖片描述

設此時有3個哈希函數,位圖數組長度為8,數據庫寫入數據x:

將該數據x得到的三個哈希值 % 位圖數據長度得到三個數組下標,填入1。

當業務線程查詢數據是否存在于數據庫時,查詢 1、4、6下標的值是否為1,若有一個為0,則說明不存在

(存在哈希沖突,故若查詢布隆過濾器說數據存在于數據庫,此時數據不一定在數據庫;但是查詢到數據不存在時,數據一定不存在)

在這里插入圖片描述
在這里插入圖片描述

更新數據時,如何保證數據庫和緩存的一致性?

1. 先更新數據庫?先更新緩存?

在數據更新時,先更新數據庫還是先更新緩存,都會存在并發問題,當兩個請求并發更新同一條數據時,可能會出現緩存和數據庫中數據不一致的現象。

解決方案

  • 更新緩存之前加分布式鎖,保證同一時間只運行一個請求更新緩存,但對寫入性能造成影響
  • 更新完緩存后,給緩存加上較短的過期時間,即使不一致,但也會很快過期

2. Cache Aside策略

旁路緩存策略: 在更新數據時,不更新緩存,更新數據庫,刪除緩存, 當讀取數據發現緩存中無該數據時,再從數據庫中讀取數據,并且寫入緩存。

(刪除緩存,不更新緩存是懶加載思想的應用)

分為讀策略、寫策略

  • 寫策略
    • 更新數據庫中的數據
    • 刪除緩存中的數據
  • 讀策略
    • 若讀取的數據命中緩存,則直接返回數據
    • 若讀取的數據沒有命中緩存,則從數據庫中讀取數據,再將該數據寫入緩存,并且返回給用戶

例:請求A讀取數據,請求B更新數據

在這里插入圖片描述

此時數據庫中為21,緩存中為20

該情況出現概率不高,因為緩存的寫入通常遠遠快于數據庫的寫入

① 先更新數據庫,再刪除緩存

先更新數據庫,再刪除緩存 可以保證“數據一致性”,并且對緩存加上過期時間,可以保證最終一致性

問題:

  • 先更新數據庫,再刪除緩存會導致緩存命中率降低。

    ? 若對緩存命中率有要求,可以采用更新數據庫+更新緩存,解決方案見1.

  • 這種方法保證數據一致性的前提是 更新數據庫和刪除緩存都能正常執行成功。

    (刪除緩存失敗時,可能出現緩存中為舊數據,數據庫中為新數據)

    保證更新數據庫、刪除緩存都執行成功

    采用異步緩存,保證第二個操作執行成功

    • 重試機制 => 引入消息隊列,將刪除緩存操作的數據加入消息隊列,由消費者操作數據
      • 如果刪除緩存失敗,從消息隊列重新讀取需要刪除的數據,再次刪除緩存(若多次刪除失敗,需要向業務層發送報錯信息)
      • 如果刪除緩存成功,把數據從消息隊列移除,避免重復操作
    • 訂閱 MySQL binlog,再操作緩存
      • 先更新數據庫,再刪除緩存,當更新數據庫成功,就會產生一條變更日志,記錄在binlog里。于是可以訂閱binlog日志,拿到具體要操作的數據,再執行緩存刪除。
      • Canal模擬MySQL的主從復制的交互協議,把自己偽裝成從節點,向MySQL主節點發送dump請求,MySQL收到請求后,推送binlog給Canal,Canal解析Binlog字節流后,轉換為便于讀取的結構化數據,供下游程序訂閱使用
        • 在這里插入圖片描述

② 先刪除緩存,再更新數據庫

出現并發問題,造成緩存、數據庫數據不一致

解決方案

延遲雙刪

  1. 刪除緩存
  2. 更新數據庫
  3. 睡眠
  4. 再刪除緩存

請求A在睡眠時,B能夠完成讀取數據庫數據,并把缺失數據寫入緩存,A睡眠完后刪除緩存。

請求A的睡眠時間 > 請求B的從數據庫讀取數據+寫入緩存的時間

該方案盡可能保持一致性,建議采用先更新數據庫,再刪除緩存

互斥鎖vs分布式鎖

互斥鎖:單機情況下,內存中的一個互斥鎖就能控制一個程序的線程并發
分布式鎖:適用于分布式場景,集群架構,需要“全局鎖”實現控制多個程序/多個機器上的線程并發

小林coding圖解Redis — 七

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

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

相關文章

【問題解決】RuntimeError: apex.optimizers.FusedSGD requires cuda extension 問題解決

在使用 apex 庫時,按照官方的方式安裝后,雖然安裝成功,但調用的時候會報錯如下,也就是說其實沒有成功安裝可調用 cuda 的 apex: RuntimeError: apex.optimizers.FusedSGD requires cuda extension我找了很多解決方式&…

【藍橋杯省賽真題46】Scratch魔術表演 藍橋杯scratch圖形化編程 中小學生藍橋杯省賽真題講解

目錄 scratch魔術表演 一、題目要求 編程實現 二、案例分析 1、角色分析

微信小程序bindtap和catchtap的區別?

子元素用bindtap綁定事件后,執行的時候,會冒泡到父元素(觸發父親元素上綁定的bindtap事件) 如果不想冒泡到父元素,可以用catchtap代替 bindtap事件綁定不會阻止冒泡事件向上冒泡 catchtap事件綁定可以阻止冒泡事件向上…

centos 7.7 安裝Python-3.7.4

一、安裝PYTHON 編譯依賴包 1.1 首先安裝gcc編譯器,gcc有些系統版本已經默認安裝,通過 gcc --version 查看,沒安裝的先安裝gcc, yum -y install gcc glibc make1.2 安裝其它依賴包,(注:不要缺…

【雙指針】和為 s 的兩個數字

和為 s 的兩個數字 文章目錄 和為 s 的兩個數字題目描述算法思路暴力枚舉雙指針 代碼編寫Java代碼C代碼編寫 LCR 179. 查找總價格為目標值的兩個商品 - 力扣(LeetCode) 題目描述 購物車內的商品價格按照升序記錄于數組 price。請在購物車中找到兩個商品…

Android修行手冊-超出父布局進行顯示以及超出父布局實現點擊

Unity3D特效百例案例項目實戰源碼Android-Unity實戰問題匯總游戲腳本-輔助自動化Android控件全解手冊再戰Android系列Scratch編程案例軟考全系列Unity3D學習專欄藍橋系列ChatGPT和AIGC 👉關于作者 專注于Android/Unity和各種游戲開發技巧,以及各種資源分…

shopee數據分析軟件丨探索Shopee數據分析軟件——知蝦

隨著電子商務的快速發展,越來越多的商家和企業開始關注數據分析的重要性。在這個競爭激烈的市場中,了解消費者行為、市場趨勢和競爭對手的策略是取得成功的關鍵。而Shopee數據分析軟件——知蝦,成為了許多商家和企業的首選工具。本文將深入探…

ubuntu20.04 nginx 部署靜態網頁

1、安裝nginx Ubuntu環境下安裝部署Nginx(有網)_ubuntu 安裝nginx_荒Huang的博客-CSDN博客 2、壓縮并上傳文件到服務器指定位置(unzip命令),修改nginx配置文件,指定root目錄為文件的目錄,index 值為指定的html文件 …

【拿完年終獎后】想要轉行網絡安全,一定不要錯過這個時間段。

網絡安全,作為當下互聯網行業中較為熱門的崗位,薪資可觀、人才需求量大,作為轉行必考慮。 在這里奉勸所有零基礎想轉行(入門) 網絡安全的朋友們 在轉行之前,一定要對網絡安全行業做一個大概了解&#xf…

latex通過bib添加參考文獻作者名字有特殊符號如字母上有兩點亂碼解決辦法

一、背景 在使用latex寫英文論文時,一般是通過bib的方式添加參考文獻。但有的參考文獻作者是法國人或其他國家的,名字會有特殊符號,如某個字母上有兩個點,或者聲調符號等等,如下圖所示: 如果不進行特殊操作…

【C++初階】第一站:C++入門基礎(中)

前言: 這篇文章是c入門基礎的第一站的中篇,涉及的知識點 函數重載:函數重載的原理--名字修飾 引用:概念、特性、使用場景、常引用、傳值、傳引用效率比較的知識點 目錄 5. 函數重載 (續) C支持函數重載的原理--名字修飾(name Mangling) 為什么…

ACE前攝器Proactor

轉載的,已經找不到原文地址了 Proactor是異步模式的網絡處理器,ACE中叫做“前攝器”。 先講幾個概念: 前攝器(Proactor)-異步的事件多路分離器、處理器,是核心處理類。啟動后由3個線程…

csv文件添加文件內容和讀取

append content to file import numpy as np acc_listnp.array([0.97,0.92,0.93,0.89]) # 注意這個地方添加文件不需要特別聲明是什么文件 file open("result.csv", "a") print("{:.2f}, {:.2f}".format(acc_list.mean(), acc_list.std()), f…

【JavaEE】Spring小練習——存儲和獲取對象

一、題目: 在 Spring 項目中,通過 main 方法獲取到 Controller 類,調用 Controller 里面通過注入的方式調用Service 類,Service 再通過注入的方式獲取到 Repository 類,Repository 類里面有一個方法構建?個 User 對象…

YOLO目標檢測——垃圾檢測數據集下載分享【含對應voc、coco和yolo三種格式標簽】

實際項目應用:智能化垃圾分類系統、垃圾回收和處理領域的優化管理等方面數據集說明:垃圾分類檢測數據集,真實場景的高質量圖片數據,數據場景豐富,含報紙、蛋殼、礦泉水瓶、電池、拉鏈頂罐、塑料餐盒、紙質藥盒、香蕉皮…

kubernetesr進階--Security Context之Security Context概述

提起 Security Context ,估計大家都很陌生,那么現在讓我帶大家走進 Security Context的世界。 Security Context(安全上下文)用來限制容器對宿主節點的可訪問范圍,以避免容器非法操作宿主節點的系統級別的內容&#x…

SpringMVC(一)

1. SpringMVC簡介 1、什么是MVC MVC是一種軟件架構的思想,將軟件按照模型、視圖、控制器來劃分 M:Model,模型層,指工程中的JavaBean,作用是處理數據 JavaBean分為兩類: 一類稱為實體類Bean&#xff1a…

創新洞察|展望2030 – 企業數字化轉型的10大趨勢(阿里研究院)

企業是否一定要 數字化創新 轉型?究竟如何數字化轉型?難點和坑又是什么?阿里研究院副院長針對未來十年中國的數字化轉型提出十個方面需要關注的趨勢:1.大國優勢 2. 重構的消費者決策體系 3. 下一代數字原生企業 4. 所有企業都會成…

【python學習】中級篇-數據庫操作:SQLite

SQLite是一個輕量級的數據庫引擎,它可以嵌入到各種應用程序中。以下是SQLite的基本用法: 創建數據庫文件 import sqlite3# 連接到一個不存在的數據庫文件,如果文件不存在,將會自動創建一個新的數據庫文件 conn sqlite3.connect…

Vue樣式不生效 如何解決它

如果使用了scoped后,無法修改第三方UI組件庫組件的樣式,這里可以使用css深度作用選擇器,以作樣式修改。 在Vue項目中,經常需要使用如elementUI、vant、 iview等組件庫,都可能自定義一些樣式文件,但是有些樣式直接在組…