網站首頁 編程語言 正文
????????緩存可以提升性能,減輕數據庫壓力,在獲取這部分好處的同時,它卻帶來了一些新的問題,緩存和數據庫之間的數據一致性問題。
想必大家在工作中只要用了咱們緩存勢必就會遇到過此類問題
首先我們來看看一致性:
- 強一致性:任何一次讀都能讀到某個數據的最近一次寫的數據。
- 弱一致性:數據更新后,如果能容忍后續的訪問只能訪問到部分或者全部訪問不到,則是弱一致性。
1.讀取數據
- 當應用程序需要從數據庫讀取數據時,先檢查緩存數據是否命中。
- 如果緩存未命中,則查詢數據庫獲取數據,同時將數據寫到緩存中,以便后續讀取相同數據會命中緩存,最后再把數據返回給調用者。
- 如果緩存命中,直接返回。
????????單獨的只讀取數據場景是不會出現不一致。 只有讀和寫一起才會出現 , 那我們再來說下寫數據的場景
問題:如果數據庫中的某條數據放入緩存后,又馬上被更新了,那我們應該如何更新緩存
2.寫數據
當我們對數據進行修改的時候,到底是先刪緩存,還是先寫數據庫?
- 先更新緩存再更新數據庫
- 先刪除緩存再更新數據庫
- 先更新數據庫再更新緩存
- 先更新數據庫再刪除緩存
無非就是緩存用更新或用刪除?推薦直接刪除
????????為什么不更新?而直接刪, 因為緩存的更新成本更高(因為你寫入數據庫的值,很多情況并不是直接寫入緩存的,而是要經過一系列復雜的計算再寫入緩存。那么,每次寫入數據庫后,都再次計算寫入緩存的值,無疑是浪費性能的。顯然,刪除緩存更為適合。)刪除緩存操作簡單,副作用只是增加了一次 chache miss,建議大家使用該策略。
先操作數據庫還是先操作緩存?
2.先操作緩存
2.1先更新緩存,再更新數據庫
缺點:如果先更新緩存成功,在更新數據庫的時候失敗,這時候會導致數據不一致;緩存的作用是不是臨時將我們數據保存在內存,便于提高查詢速度;但是如果某條數據在數據庫中都不存在,緩存這種數據沒有一點意義
2.2.先刪除緩存,再更新數據庫
缺點:高并發場景下,如果多個線程同時執行更新數據庫再寫緩存操作可能會出現數據庫是新值,而緩存中是舊值
2.3.先刪緩存再刪數據庫?
????????先刪緩存再刪數據庫:在多線程環境下,當一個線程把緩存刪掉之后,另一個線程讀緩存,讀不到緩存就會直接讀庫,讀到數據后就會更新緩存,先前的線程呢,才更新數據庫,會造成緩存臟讀的情況,很容易產生緩存臟讀。
而且,如果不采用給緩存設置過期時間策略,該數據永遠都是臟數據。
3.先操作數據庫
3.1.先更新數據庫,再更新緩存
優點:可以解決先更新緩存,再更新數據庫帶來的假數據問題
缺點:高并發場景下,如果多個線程同時執行更新數據庫再寫緩存操作可能會出現數據庫是新值,而緩存中是舊值
3.2.先更新數據庫,再刪除緩存
????????在高可用的系統系統里面,我們追求數據最終一致性的話,我們可以考慮先更新數據庫,再去刪除緩存
? ? ? ? 也算是常用的方案,這里介紹一下,這個叫 Cache Aside Pattern。如果先更新數據庫,再刪除緩存,那么就會出現更新數據庫之前有瞬間數據不是很及時。
????????同時,如果在更新之前,緩存剛好失效了,讀客戶端有可能讀到舊值,然后在寫客戶端刪除結束后再次設置了舊值,非常巧合的情況。
????????有 2 個前提條件:緩存在寫之前的時候失效,同時,在寫客戶度刪除操作結束后,放置舊數據 — 也就是讀比寫慢。設置有的寫操作還會鎖表。
這個很難出現,但是如果出現了怎么辦?使用雙刪!!!
3.3先刪數據庫再刪緩存?
先刪數據庫再刪緩存,在多線程情況下,當一個線程刪除數據庫,另一個線程讀取緩存數據,讀到的是緩存的數據,當先前一個線程刪完數據庫后就會更新緩存,這是緩存就正常了,產生了一次臟讀。?
5.解決
5.1.強一致性?
在強一致性系統中,通過2PC、Paxos或分布式鎖保持一致性可能會成為影響系統吞吐量、響應時間和可伸縮性的昂貴開銷, 因此通常采用一種相當寬松的一致性方法,稱為最終一致性。
5.2.最終一致性:延時雙刪
關鍵:間隔一段時間再刪除是為了保證并發讀請求寫入的舊值最終能夠被第二次刪除刪除掉
缺點:延時雙刪可能對我們性能要求方面不能有太高的要求
注意:我們需要自行評估項目的讀數據業務邏輯的耗時(即線程二從數據庫讀取數據 寫入緩存完成), 防止線程二覆蓋掉新數據
如果第二次刪除緩存失敗怎么辦?
4.為了防止刪除緩存失敗,可以進行重試機制
- 同步重試,如果并發量高的時候可能會影響接口性能
- 異步重試:
- 創建單獨的一個線程,進行重試;但是在高并發的場景下,可能會因為創建線程太多,導致OOM
- 交給線程池處理;但是如果服務重啟,會導致數據丟失
- 重試數據寫入表,通過定時任務重試(可以保證數據不丟失,但是對于實時性要求較高的該場景不太適用)
- 利用MQ消息中間件進行重試,在消費者中處理
- 訂閱mysql的binlong,在訂閱者中,如果發現更新數據請求,則刪除響應的緩存,比如使用canal中間件;為了保證刪除緩存成功,可以增加MQ
6.總結?
緩存策略的最佳實踐是 **Cache Aside Pattern。**分別分為讀緩存最佳實踐和寫緩存最佳實踐。
讀緩存最佳實踐:先讀緩存,命中則返回;未命中則查詢數據庫,再寫到數據庫。
寫緩存最佳實踐:
- 先寫數據庫,再操作緩存;
- 直接刪除緩存,而不是修改,因為緩存的更新成本很高,刪除緩存操作簡單,副作用只是增加了一次 chache miss,建議大家使用該策略。
在以上最佳實踐下,為了盡可能保證緩存與數據庫的一致性,我們可以采用延遲雙刪。
防止刪除失敗,我們采用異步重試機制保證能正確刪除,異步機制我們可以發送刪除消息到 mq 消息中間件,或者利用 canal 訂閱 MySQL binlog 日志監聽寫請求刪除對應緩存。
那么,如果我非要保證絕對一致性怎么辦,先給出結論:
沒有辦法做到絕對的一致性,這是由 CAP 理論決定的,緩存系統適用的場景就是非強一致性的場景,所以它屬于 CAP 中的 AP。
所以,我們得委曲求全,可以去做到 BASE 理論中說的最終一致性。
其實一旦在方案中使用了緩存,那往往也就意味著我們放棄了數據的強一致性,但這也意味著我們的系統在性能上能夠得到一些提升。
原文鏈接:https://blog.csdn.net/qq_20957669/article/details/136711239
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2023-07-10 解決flask (flask-restful)中文亂碼問題
- 2022-04-27 Numpy的各種下標操作的示例代碼_python
- 2022-06-14 Flutter網絡請求Dio庫的使用及封裝詳解_Android
- 2022-11-18 React?Immutable使用方法詳細介紹_React
- 2024-01-07 SpringSecurity Oauth2 解決 The bean ‘metaDataSourceA
- 2022-12-14 Android?Studio?gradle配置packagingOptions打包so庫重復_And
- 2022-05-05 Python學習之流程控制與條件判斷總結_python
- 2022-02-04 UMP系統設計了如下機制來保證數據安全
- 欄目分類
-
- 最近更新
-
- 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同步修改后的遠程分支