網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
????????緩存可以提升性能,減輕數(shù)據(jù)庫(kù)壓力,在獲取這部分好處的同時(shí),它卻帶來了一些新的問題,緩存和數(shù)據(jù)庫(kù)之間的數(shù)據(jù)一致性問題。
想必大家在工作中只要用了咱們緩存勢(shì)必就會(huì)遇到過此類問題
首先我們來看看一致性:
- 強(qiáng)一致性:任何一次讀都能讀到某個(gè)數(shù)據(jù)的最近一次寫的數(shù)據(jù)。
- 弱一致性:數(shù)據(jù)更新后,如果能容忍后續(xù)的訪問只能訪問到部分或者全部訪問不到,則是弱一致性。
1.讀取數(shù)據(jù)
- 當(dāng)應(yīng)用程序需要從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)時(shí),先檢查緩存數(shù)據(jù)是否命中。
- 如果緩存未命中,則查詢數(shù)據(jù)庫(kù)獲取數(shù)據(jù),同時(shí)將數(shù)據(jù)寫到緩存中,以便后續(xù)讀取相同數(shù)據(jù)會(huì)命中緩存,最后再把數(shù)據(jù)返回給調(diào)用者。
- 如果緩存命中,直接返回。
????????單獨(dú)的只讀取數(shù)據(jù)場(chǎng)景是不會(huì)出現(xiàn)不一致。 只有讀和寫一起才會(huì)出現(xiàn) , 那我們?cè)賮碚f下寫數(shù)據(jù)的場(chǎng)景
問題:如果數(shù)據(jù)庫(kù)中的某條數(shù)據(jù)放入緩存后,又馬上被更新了,那我們應(yīng)該如何更新緩存
2.寫數(shù)據(jù)
當(dāng)我們對(duì)數(shù)據(jù)進(jìn)行修改的時(shí)候,到底是先刪緩存,還是先寫數(shù)據(jù)庫(kù)?
- 先更新緩存再更新數(shù)據(jù)庫(kù)
- 先刪除緩存再更新數(shù)據(jù)庫(kù)
- 先更新數(shù)據(jù)庫(kù)再更新緩存
- 先更新數(shù)據(jù)庫(kù)再刪除緩存
無非就是緩存用更新或用刪除?推薦直接刪除
????????為什么不更新?而直接刪, 因?yàn)?strong>緩存的更新成本更高(因?yàn)槟銓懭霐?shù)據(jù)庫(kù)的值,很多情況并不是直接寫入緩存的,而是要經(jīng)過一系列復(fù)雜的計(jì)算再寫入緩存。那么,每次寫入數(shù)據(jù)庫(kù)后,都再次計(jì)算寫入緩存的值,無疑是浪費(fèi)性能的。顯然,刪除緩存更為適合。)刪除緩存操作簡(jiǎn)單,副作用只是增加了一次 chache miss,建議大家使用該策略。
先操作數(shù)據(jù)庫(kù)還是先操作緩存?
2.先操作緩存
2.1先更新緩存,再更新數(shù)據(jù)庫(kù)
缺點(diǎn):如果先更新緩存成功,在更新數(shù)據(jù)庫(kù)的時(shí)候失敗,這時(shí)候會(huì)導(dǎo)致數(shù)據(jù)不一致;緩存的作用是不是臨時(shí)將我們數(shù)據(jù)保存在內(nèi)存,便于提高查詢速度;但是如果某條數(shù)據(jù)在數(shù)據(jù)庫(kù)中都不存在,緩存這種數(shù)據(jù)沒有一點(diǎn)意義
2.2.先刪除緩存,再更新數(shù)據(jù)庫(kù)
缺點(diǎn):高并發(fā)場(chǎng)景下,如果多個(gè)線程同時(shí)執(zhí)行更新數(shù)據(jù)庫(kù)再寫緩存操作可能會(huì)出現(xiàn)數(shù)據(jù)庫(kù)是新值,而緩存中是舊值
2.3.先刪緩存再刪數(shù)據(jù)庫(kù)?
????????先刪緩存再刪數(shù)據(jù)庫(kù):在多線程環(huán)境下,當(dāng)一個(gè)線程把緩存刪掉之后,另一個(gè)線程讀緩存,讀不到緩存就會(huì)直接讀庫(kù),讀到數(shù)據(jù)后就會(huì)更新緩存,先前的線程呢,才更新數(shù)據(jù)庫(kù),會(huì)造成緩存臟讀的情況,很容易產(chǎn)生緩存臟讀。
而且,如果不采用給緩存設(shè)置過期時(shí)間策略,該數(shù)據(jù)永遠(yuǎn)都是臟數(shù)據(jù)。
3.先操作數(shù)據(jù)庫(kù)
3.1.先更新數(shù)據(jù)庫(kù),再更新緩存
優(yōu)點(diǎn):可以解決先更新緩存,再更新數(shù)據(jù)庫(kù)帶來的假數(shù)據(jù)問題
缺點(diǎn):高并發(fā)場(chǎng)景下,如果多個(gè)線程同時(shí)執(zhí)行更新數(shù)據(jù)庫(kù)再寫緩存操作可能會(huì)出現(xiàn)數(shù)據(jù)庫(kù)是新值,而緩存中是舊值
3.2.先更新數(shù)據(jù)庫(kù),再刪除緩存
????????在高可用的系統(tǒng)系統(tǒng)里面,我們追求數(shù)據(jù)最終一致性的話,我們可以考慮先更新數(shù)據(jù)庫(kù),再去刪除緩存
? ? ? ? 也算是常用的方案,這里介紹一下,這個(gè)叫 Cache Aside Pattern。如果先更新數(shù)據(jù)庫(kù),再刪除緩存,那么就會(huì)出現(xiàn)更新數(shù)據(jù)庫(kù)之前有瞬間數(shù)據(jù)不是很及時(shí)。
????????同時(shí),如果在更新之前,緩存剛好失效了,讀客戶端有可能讀到舊值,然后在寫客戶端刪除結(jié)束后再次設(shè)置了舊值,非常巧合的情況。
????????有 2 個(gè)前提條件:緩存在寫之前的時(shí)候失效,同時(shí),在寫客戶度刪除操作結(jié)束后,放置舊數(shù)據(jù) — 也就是讀比寫慢。設(shè)置有的寫操作還會(huì)鎖表。
這個(gè)很難出現(xiàn),但是如果出現(xiàn)了怎么辦?使用雙刪!!!
3.3先刪數(shù)據(jù)庫(kù)再刪緩存?
先刪數(shù)據(jù)庫(kù)再刪緩存,在多線程情況下,當(dāng)一個(gè)線程刪除數(shù)據(jù)庫(kù),另一個(gè)線程讀取緩存數(shù)據(jù),讀到的是緩存的數(shù)據(jù),當(dāng)先前一個(gè)線程刪完數(shù)據(jù)庫(kù)后就會(huì)更新緩存,這是緩存就正常了,產(chǎn)生了一次臟讀。?
5.解決
5.1.強(qiáng)一致性?
在強(qiáng)一致性系統(tǒng)中,通過2PC、Paxos或分布式鎖保持一致性可能會(huì)成為影響系統(tǒng)吞吐量、響應(yīng)時(shí)間和可伸縮性的昂貴開銷, 因此通常采用一種相當(dāng)寬松的一致性方法,稱為最終一致性。
5.2.最終一致性:延時(shí)雙刪
關(guān)鍵:間隔一段時(shí)間再刪除是為了保證并發(fā)讀請(qǐng)求寫入的舊值最終能夠被第二次刪除刪除掉
缺點(diǎn):延時(shí)雙刪可能對(duì)我們性能要求方面不能有太高的要求
注意:我們需要自行評(píng)估項(xiàng)目的讀數(shù)據(jù)業(yè)務(wù)邏輯的耗時(shí)(即線程二從數(shù)據(jù)庫(kù)讀取數(shù)據(jù) 寫入緩存完成), 防止線程二覆蓋掉新數(shù)據(jù)
如果第二次刪除緩存失敗怎么辦?
4.為了防止刪除緩存失敗,可以進(jìn)行重試機(jī)制
- 同步重試,如果并發(fā)量高的時(shí)候可能會(huì)影響接口性能
- 異步重試:
- 創(chuàng)建單獨(dú)的一個(gè)線程,進(jìn)行重試;但是在高并發(fā)的場(chǎng)景下,可能會(huì)因?yàn)閯?chuàng)建線程太多,導(dǎo)致OOM
- 交給線程池處理;但是如果服務(wù)重啟,會(huì)導(dǎo)致數(shù)據(jù)丟失
- 重試數(shù)據(jù)寫入表,通過定時(shí)任務(wù)重試(可以保證數(shù)據(jù)不丟失,但是對(duì)于實(shí)時(shí)性要求較高的該場(chǎng)景不太適用)
- 利用MQ消息中間件進(jìn)行重試,在消費(fèi)者中處理
- 訂閱mysql的binlong,在訂閱者中,如果發(fā)現(xiàn)更新數(shù)據(jù)請(qǐng)求,則刪除響應(yīng)的緩存,比如使用canal中間件;為了保證刪除緩存成功,可以增加MQ
6.總結(jié)?
緩存策略的最佳實(shí)踐是 **Cache Aside Pattern。**分別分為讀緩存最佳實(shí)踐和寫緩存最佳實(shí)踐。
讀緩存最佳實(shí)踐:先讀緩存,命中則返回;未命中則查詢數(shù)據(jù)庫(kù),再寫到數(shù)據(jù)庫(kù)。
寫緩存最佳實(shí)踐:
- 先寫數(shù)據(jù)庫(kù),再操作緩存;
- 直接刪除緩存,而不是修改,因?yàn)?strong>緩存的更新成本很高,刪除緩存操作簡(jiǎn)單,副作用只是增加了一次 chache miss,建議大家使用該策略。
在以上最佳實(shí)踐下,為了盡可能保證緩存與數(shù)據(jù)庫(kù)的一致性,我們可以采用延遲雙刪。
防止刪除失敗,我們采用異步重試機(jī)制保證能正確刪除,異步機(jī)制我們可以發(fā)送刪除消息到 mq 消息中間件,或者利用 canal 訂閱 MySQL binlog 日志監(jiān)聽寫請(qǐng)求刪除對(duì)應(yīng)緩存。
那么,如果我非要保證絕對(duì)一致性怎么辦,先給出結(jié)論:
沒有辦法做到絕對(duì)的一致性,這是由 CAP 理論決定的,緩存系統(tǒng)適用的場(chǎng)景就是非強(qiáng)一致性的場(chǎng)景,所以它屬于 CAP 中的 AP。
所以,我們得委曲求全,可以去做到 BASE 理論中說的最終一致性。
其實(shí)一旦在方案中使用了緩存,那往往也就意味著我們放棄了數(shù)據(jù)的強(qiáng)一致性,但這也意味著我們的系統(tǒng)在性能上能夠得到一些提升。
原文鏈接:https://blog.csdn.net/qq_20957669/article/details/136711239
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2023-12-11 Spring利用注解自動(dòng)裝配
- 2023-04-22 Python中DataFrame與內(nèi)置數(shù)據(jù)結(jié)構(gòu)相互轉(zhuǎn)換的實(shí)現(xiàn)_python
- 2023-02-02 Nginx顯示500錯(cuò)誤的原因以及解決方法_nginx
- 2022-04-25 C++特殊成員函數(shù)以及其生成機(jī)制詳解_C 語(yǔ)言
- 2022-09-13 Android?Studio實(shí)現(xiàn)簡(jiǎn)單補(bǔ)間動(dòng)畫_Android
- 2022-08-01 C語(yǔ)言深入探索遞歸的特點(diǎn)_C 語(yǔ)言
- 2022-04-17 Security前后端分離自定義登錄詳解
- 2022-12-10 C語(yǔ)言中使用qsort函數(shù)對(duì)自定義結(jié)構(gòu)體數(shù)組進(jìn)行排序_C 語(yǔ)言
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支