網站首頁 編程語言 正文
一、Redis三種常用的緩存讀寫策略
Redis有三種讀寫策略分別是:旁路緩存模式策略、讀寫穿透策略、異步緩存寫入策略。
這三種緩存讀寫策略各有優勢,不存在最佳,需要我們根據實際的業務場景選擇最合適的。
二、旁路緩存模式(Cache Aside Pattern)
旁路緩存模式是我們平時使用比較多的一個緩存讀寫模式,比較適合讀請求比較多的場景。
旁路緩存模式中服務端需要同時維護DB
和Cache
,并且是以DB
的結果為準。
讀寫步驟
寫:
- 先更新
DB
。 - 然后直接刪除
cache
。
如下圖:
讀:
- 從
cache
中讀取數據,讀取到就直接返回。 -
cache
中讀取不到的話,就從DB
讀取返回。 - 再把數據寫到
cache
中。
如下圖:
自我思考
思考這樣子的一個問題:“如果在寫數據的過程中,可以先刪除cache,再更新DB嗎? ”
答案: 答案肯定是不行的,因為這樣子可能造成數據庫和緩存數據不一致的問題,比如這個時候有一個數據在DB和緩存都為100,請求1需要將這個數據更新寫成200,如果先刪除換出再更新數據庫的話,在請求1已經刪除緩存但是數據庫還沒寫完的時候,有一個請求2讀取數據,首先去緩存讀取,發現緩存被刪除了,然后去數據庫讀取得到100(這個時候請求1還沒寫完)再寫入緩存,這個時候請求1寫完了,這個時候數據庫里數據為200,緩存里為100,不一致。
可以簡單描述為:
請求1先把cache中的數據刪除 -> 請求2從DB中讀取數據 -> 請求1再把DB中的數據更新
緊接著思考:“在寫數據的過程中,如果先寫BD,再刪除cache就不會造成數據不一致了嗎? ”
答案: 理論上來說還是會出現數據不一致的問題,不過概率很小,因為緩存的寫入速度是比數據庫寫入速度快很多。
比如請求1先讀數據A,請求2隨后寫數據A,并且數據A不在緩存中存在的話就會去數據庫讀取,讀取完請求2再更新完并刪除緩存,然后請求1把數據A寫入緩存,這個時候數據庫和緩存就不一致了。
這個過程可以簡單的描述為:
請求1從DB讀取數據A -> 請求2寫更新數據A到數據庫再刪除cache中的A數據 -> 請求1將數據A寫入緩存
缺點
-
首次請求的數據一定不在cache的問題
解決辦法:可以將熱點數據提前寫入
cache
中。 -
寫操作比較頻繁的話導致cache中的數據會被頻繁的刪除,這樣會影響緩存命中率。
解決辦法:
- 數據庫和緩存強一直場景:更新
DB
的時候同樣更新cache
,不過需要加一個鎖/分布式鎖來保證更新cache
的時候不存在線程安全問題。 - 可以短暫的允許數據庫和緩存數據不一致的場景:更新
DB
的時候同樣更新cache
,但是給緩存加一個比較短的過期時間,這樣的話就可以保證即使數據不一致的話影響也比較小。
- 數據庫和緩存強一直場景:更新
三、讀寫穿透(Read/Write Through Pattern)
讀寫穿透中服務端把cache
視為主要數據存儲,從中讀取數據并將數據寫入其中。cache
服務負責將此數據讀取和寫入DB
,從而減輕應用程序的職責。
讀寫步驟
寫:
- 先查
cache
,cache
中不存在,直接更新DB
。 -
cache
中存在,則先更新cache
,然后cache
服務自己更新DB
(同時更新DB
和cache
)。
如下圖:
讀:
- 先從
cache
中讀取數據,讀取到直接返回。 - 從
cache
中讀取不到,則先從DB
加載寫入到cache
后返回響應。
如下圖:
讀寫穿透實際是在旁路緩存之上進行了封裝。在旁路緩存下,發生讀請求的時候,如果cache
中不存在對應的數據,是由客戶端自己負責把數據寫入cache
,而讀寫穿透則是cache
服務自己來寫入緩存,這對客戶端是透明的。
和旁路緩存一樣,讀寫穿透也存在首次請求數據一定不在cache
中的問題,對于熱點數據可以提前寫入緩存中。
四、異步緩存寫入(Write Behind Pattern)
異步緩存寫入和讀寫穿透很相似,兩者都是由cache
服務來負責cache
和DB
的讀寫。
兩者最大的不同點就是:讀寫穿透是同步更新DB
和cache
,而異步緩存寫入則是只更新cache
,不直接更新DB
,而是改為異步批量的方式更新DB
。
很明顯,這種方式對數據一致性帶來了更大的挑戰,比如cache
數據可能還沒異步更新DB
,cache
服務可能就掛了。
這種策略在我們平時開發過程中也非常少見,但是不代表它的應用場景少,比如消息隊列中消息的異步寫入磁盤、MySQL
的InnoDB Buffer Pool
機制都用到了這種策略。
異步緩存寫入的寫性能非常高,非常適合寫數據經常變化又對數據一致性要求沒那么高的場景下使用,比如瀏覽量、點贊量等。
參考:javaguide.cn/database/re…
原文鏈接:https://juejin.cn/post/7093452218535247886
相關推薦
- 2022-08-07 詳解Qt使用QImage類實現圖像基本操作_C 語言
- 2022-06-24 Edge瀏覽器開發者工具代碼修改同步到Vscode中_網頁編輯器
- 2022-10-17 C++智能指針模板應用詳細介紹_C 語言
- 2022-08-10 C#對文件名智能排序的算法_C#教程
- 2022-05-05 Entity?Framework使用Fluent?API配置案例_實用技巧
- 2022-04-22 Error:Module “./antd/es/badge/style“ does not exis
- 2023-03-28 python數組如何添加整行或整列_python
- 2022-09-26 Redis刪除策略的三種方法及逐出算法_Redis
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支