Redis的緩存一致性問題詳解

来源:https://www.cnblogs.com/pxypxy/archive/2023/03/13/17212828.html
-Advertisement-
Play Games

摘要:行存表示了一種數據的存儲方式,是最傳統的一種存儲方式。 本文分享自華為雲社區《【玩轉PB級數倉GaussDB(DWS)】行列存對比的一些事》,作者:sevenjiang。 行存表示了一種數據的存儲方式,是最傳統的一種存儲方式。對於GaussDB(DWS)來說可以認為其表示存儲引擎的基礎實現,在 ...


1、三種常用的緩存模式

1.旁路緩存模式

一般來說,如果允許緩存可以稍微的跟資料庫偶爾有不一致的情況,也就是說如果你的系統不是嚴格要求 “緩存+資料庫” 必須保持一致性的話,最好不要做這個方案,即:讀請求和寫請求串列化串到一個記憶體隊列里去。

採用緩存 + 資料庫讀寫的方式,就是 Cache Aside Pattern(旁路緩存模式)。

  • 讀的時候,先讀緩存,緩存沒有的話,就讀資料庫,然後取出數據後放入緩存,同時返迴響應。
  • 更新的時候,先更新資料庫,然後再刪除緩存

2.讀寫穿透模式

Read/Write Through Pattern 中服務端把 cache 視為主要數據存儲,從中讀取數據並將數據寫入其中。cache 服務負責將此數據讀取和寫入 db,從而減輕了應用程式的職責。

寫(Write Through):先查 cache,cache 中不存在,直接更新 db;cache 中存在,則先更新 cache,然後 cache 服務自己更新 db(同步更新 cache 和 db

讀(Read Through):從 cache 中讀取數據,讀取到就直接返回 ;讀取不到的話,先從 db 載入,寫入到 cache 後返迴響應。

Read-Through Pattern 實際只是在 Cache-Aside Pattern 之上進行了封裝。在 Cache-Aside Pattern 下,發生讀請求的時候,如果 cache 中不存在對應的數據,是由客戶端自己負責把數據寫入 cache,而 Read Through Pattern 則是 cache 服務自己來寫入緩存的,這對客戶端是透明的。和 Cache Aside Pattern 一樣, Read-Through Pattern 也有首次請求數據一定不再 cache 的問題,對於熱點數據可以提前放入緩存中。

3.非同步緩存寫入

非同步緩存寫入(Write Behind Pattern) 和 Read/Write Through Pattern 很相似,兩者都是由 cache 服務來負責 cache 和 db 的讀寫。

但是,兩個又有很大的不同:Read/Write Through 是同步更新 cache 和 db,而 Write Behind 則是只更新緩存,不直接更新 db,而是改為非同步批量的方式來更新 db。

很明顯,這種方式對數據一致性帶來了更大的挑戰,比如 cache 數據可能還沒非同步更新 db 的話,cache 服務可能就就掛掉了。

這種策略在我們平時開發過程中也非常非常少見,但是不代表它的應用場景少,比如消息隊列中消息的非同步寫入磁碟、MySQL 的 Innodb Buffer Pool 機制都用到了這種策略。

Write Behind Pattern 下 db 的寫性能非常高,非常適合一些數據經常變化又對數據一致性要求沒那麼高的場景,比如瀏覽量、點贊量。

2、緩存存在的問題?

1.為什麼先更新後刪除?

結論:無論先刪除還是先更新資料庫都存在數據一致性問題,那麼矮個子里選將軍,選個發生問題概率小的,就是先更新資料庫後刪除緩存。

先刪除緩存,再更新資料庫:如果刪除緩存失敗了,那麼會導致資料庫中是新數據,緩存中是舊數據,數據就出現了不一致。

2 個線程要併發「讀寫」數據,可能會發生以下場景:

  1. 線程 A 要更新 X = 2(原值 X = 1)
  2. 線程 A 先刪除緩存
  3. 線程 B 讀緩存,發現不存在,從資料庫中讀取到舊值(X = 1)
  4. 線程 A 將新值寫入資料庫(X = 2)
  5. 線程 B 將舊值寫入緩存(X = 1)

最終 X 的值在緩存中是 1(舊值),在資料庫中是 2(新值),發生不一致。

先更新資料庫,再刪除緩存:先刪除了緩存,然後要去修改資料庫,此時還沒修改。一個請求過來,去讀緩存,發現緩存空了,去查詢資料庫,查到了修改前的舊數據,並將其放到了緩存中。隨後數據變更的程式完成了資料庫的修改。資料庫和緩存中的數據不一樣了

  1. 緩存中 X 不存在(資料庫 X = 1)
  2. 線程 A 讀取資料庫,得到舊值(X = 1)
  3. 線程 B 更新資料庫(X = 2)
  4. 線程 B 刪除緩存
  5. 線程 A 將舊值寫入緩存(X = 1)

最終 X 的值在緩存中是 1(舊值),在主從庫中是 2(新值),也發生不一致。

這 2 個問題的核心在於:緩存都被回種了「舊值」

矮個子里選將軍

第二種方法其實概率很低,這是因為它必須滿足 3 個條件:

  1. 緩存剛好已失效
  2. 讀請求 + 寫請求併發
  3. 更新資料庫 + 刪除緩存的時間(步驟 3-4),要比讀資料庫 + 寫緩存時間短(步驟 2 和 5)

仔細想一下,條件 3 發生的概率其實是非常低的。

因為寫資料庫一般會先「加鎖」,所以更新資料庫,通常是要比讀資料庫的時間更長的,並且因為緩存的寫入速度是比資料庫的寫入速度快很多。這麼來看,「先更新資料庫 + 再刪除緩存」的方案,是可以保證數據一致性的。所以,我們應該採用這種方案,來操作資料庫和緩存。

2.解決方法

最有效的辦法就是,把緩存刪掉。但是,不能立即刪,而是需要「延遲刪」,即:緩存延遲雙刪策略

解決第一個問題:線上程 A 刪除緩存、更新完資料庫之後,先「休眠一會」,再「刪除」一次緩存。

解決第二個問題:線程 A 可以生成一條「延時消息」,寫到消息隊列中,消費者延時「刪除」緩存。

這兩個方案的目的,都是為了把緩存清掉,這樣一來,下次就可以從資料庫讀取到最新值,寫入緩存。

3.如何保證刪除緩存成功?

方案一:重試

首先想到的一個方案是:執行失敗後,重試。失敗後立即重試的問題在於:

  • 立即重試很大概率「還會失敗」
  • 「重試次數」設置多少才合理?
  • 重試會一直「占用」這個線程資源,無法服務其它客戶端請求

方案二:非同步重試

非同步重試其實就是:把重試請求扔到「消息隊列」中,然後由專門的消費者來重試,直到成功。把重試或第二步操作放到另一個服務中,這個服務用消息隊列來進行重試操作。

3、非同步重試方案-canal

我們的業務應用在修改數據時,「只需」修改資料庫,無需操作緩存。拿 MySQL 舉例,當一條數據發生修改時,MySQL 就會產生一條變更日誌(Binlog),我們可以訂閱這個日誌,拿到具體操作的數據,然後再根據這條數據,去刪除對應的緩存。訂閱變更日誌,目前也有了比較成熟的開源中間件,例如阿裡的 canal,使用這種方案的優點在於:

  • 無需考慮寫消息隊列失敗情況:只要寫 MySQL 成功,Binlog 肯定會有
  • 自動投遞到下游隊列:canal 自動把資料庫變更日誌「投遞」給下游的消息隊列

想要保證資料庫和緩存一致性,推薦採用「先更新資料庫,再刪除緩存」方案,並配合「消息隊列」或「訂閱變更日誌」的方式來做

圖片

參考: https://www.cnblogs.com/myseries/p/12068845.html

3種常用的緩存讀寫策略詳解

緩存和資料庫一致性問題,看這篇就夠了 - 水滴與銀彈


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

-Advertisement-
Play Games
更多相關文章
  • 1. 垃圾回收器 1.1. 對象可以在被需要時創建,不再使用時由JVM自動回收 1.2. GC是查找不再使用的對象,然後回收這些對象相關記憶體的過程 1.2.1. 找到不使用的對象、回收其記憶體、壓縮堆記憶體 1.3. 優化垃圾回收器比跟蹤指針引起的bug要容易得多(且耗時更少) 1.4. VM必須定期搜 ...
  • 簡介 Dapper是介於Entity framework與ADO的折中選擇。既滿足手寫查詢的高性能需求,又簡化了資料庫對象映射為記憶體對象的繁雜工作。Dapper.Contrib是對Dapper的進一步封裝,使對象的基本增刪改查等操作進一步簡化。 為什麼使用Dapper.Contrib 如果僅僅使用D ...
  • 在運行期間,我們可以使用 `Emit` 來組織一段 IL 代碼,進而動態生成一個方法,甚至是一個程式集(包括類型、方法或屬性等等)。這個過程我們稱之為動態編織。這一項技術應用比較廣泛,比如數據映射(Dapper)、動態代理(AOP)等等,目的是提升大量反射而產生的性能問題。 ...
  • Blazor Server,即運行在伺服器上的 Blazor 應用程式,它的優點是應用程式在首次運行時,客戶端不需要下載運行時。但它的代碼是在伺服器上執行的,然後通過 SignalR 通信來更新客戶端的 UI,所以它要求必須建立 Web Socket 連接。 用於 Blazor 應用的 Signal ...
  • 前言 假設你正在玩一款線上多人游戲,在游戲中,有多個角色需要進行不同的操作,例如攻擊、移動、釋放技能等等。 接下來,我們用玩游戲的例子,來解釋進程和和線程的概念,以及進程和線程的區別。 進程的基本概念 我們可以將整個游戲看作一個進程,它是操作系統中資源分配的基本單位,擁有自己的地址空間、記憶體、CPU ...
  • 1. ip命令 1.1. 摘要 ip是iproute2軟體包裡面的一個強大的網路配置工具,它能夠替代一些傳統的網路管理工具。例如:ifconfig、route等。這個手冊將分章節介紹ip命令及其選項。 1.2. ip命令的語法 ip命令的用法如下: [root@node01 ~]# ip Usage ...
  • 1 許可權基本介紹 drwxr-xr-x. 3 laffy snow 4096 3月 9 16:17 test 第1位:文件類型(d,-,l,c,b) d 文件夾 - 普通文件 l 軟鏈接 c 字元設備文件,如滑鼠鍵盤 b 塊設備,如硬碟 第2-4位:確定文件所有者對文件的許可權 第5-7位:確定文件所 ...
  • 在 WebAssembly 中使用 Rust 編寫 eBPF 程式併發布 OCI 鏡像 作者:於桐,鄭昱笙 eBPF(extended Berkeley Packet Filter)是一種高性能的內核虛擬機,可以運行在內核空間中,以收集系統和網路信息。隨著電腦技術的不斷發展,eBPF 的功能日益強 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...