詳解如何保證Java本地緩存的一致性
有人可能看到“本地緩存”這四個(gè)字就會(huì)覺得不屑,“哼,現(xiàn)在誰還用本地緩存?直接用分布式緩存不就完了嘛”。
然而,這就像你有一輛超級(jí)豪華的房車一樣,雖然它空間很大,設(shè)備很全,但你去市中心的時(shí)候,依然會(huì)開小轎車一樣,為啥?好停車?。∷?,不同的緩存類型是有不同得使用場(chǎng)景的。
并且,為了防止緩存雪崩問題、緩存擊穿問題,我們通常會(huì)采用多級(jí)緩存的解決方案,所謂的多級(jí)緩存就是:分布式緩存(Redis 或 Memcached)+本地緩存(Guava Cache 或 Caffeine)。因?yàn)榉植际骄彺婵赡軙?huì)失效、可能會(huì)掛掉,所以為了系統(tǒng)的穩(wěn)定性,多級(jí)緩存策略使用的非常廣泛。
那么,問題來了,怎么保證本地緩存的一致性?
所謂的一致性是指在同時(shí)使用緩存和數(shù)據(jù)庫的場(chǎng)景下,要確保數(shù)據(jù)在緩存與數(shù)據(jù)庫中的更新操作保持同步。也就是當(dāng)對(duì)數(shù)據(jù)進(jìn)行修改時(shí),無論是先修改緩存還是先修改數(shù)據(jù)庫,最終都要保證兩者的數(shù)據(jù)是一樣的,不會(huì)出現(xiàn)數(shù)據(jù)不一樣的問題。
1.如何保證本地緩存的一致性?
在分布式系統(tǒng)中,使用本地緩存最大的問題就是一致性問題,所謂的一致性問題指的是當(dāng)數(shù)據(jù)庫發(fā)生數(shù)據(jù)變更時(shí),緩存也要跟著一起變更。而分布式系統(tǒng)中每臺(tái)機(jī)器都有自己的本地緩存,所以想要保證(本地緩存的)一致性是一個(gè)比較難的問題,但通過以下手段可以最大程度的保證本地緩存的一致性問題。
① 設(shè)置本地緩存短時(shí)間內(nèi)失效
設(shè)置本地緩存短時(shí)間內(nèi)失效,短的存活周期,保證了數(shù)據(jù)的時(shí)效性比較高,當(dāng)數(shù)據(jù)失效之后,再次訪問數(shù)據(jù)就會(huì)拉取新的數(shù)據(jù)了,這樣能盡可能的保證數(shù)據(jù)的一致性。
它的特點(diǎn)是:代碼實(shí)現(xiàn)簡(jiǎn)單,不需要寫多余的代碼;缺點(diǎn)是,效果不是很明顯,不適合高并發(fā)的系統(tǒng)。
② 通過配置中心協(xié)調(diào)和同步
通過微服務(wù)中的配置中心(例如 Nacos)來協(xié)調(diào),因?yàn)樗蟹?wù)器都會(huì)連接到配置中心,所以當(dāng)數(shù)據(jù)修改之后,可以修改配置中心的配置,然后配置中心再把配置變更的事件推送給各個(gè)服務(wù),各個(gè)服務(wù)感知到配置中心的配置發(fā)生更改之后,再更新自己的本地緩存,這樣就實(shí)現(xiàn)了本地緩存的數(shù)據(jù)一致性。
③ 本地緩存自動(dòng)更新功能
使用本地緩存框架的自動(dòng)更新功能,例如 Caffeine 中的 refresh 功能來自動(dòng)刷新緩存,這樣就可以設(shè)置很短的時(shí)間來更新最新的數(shù)據(jù),從而也能盡可能的保證數(shù)據(jù)的一致性,如下代碼所示:
// 創(chuàng)建 Caffeine 緩存實(shí)例 Cache<String, String> caffeineCache = Caffeine.newBuilder() // 設(shè)置緩存項(xiàng)在 5s 后開始自動(dòng)更新 .refreshAfterWrite(5, TimeUnit.SECONDS) // 自定義緩存更新邏輯(即獲取新值邏輯) .build(new CacheLoader<String, String>() { @Override public void reload(String key, String oldValue) throws Exception { // 模擬更新緩存的操作 updateCache(key, oldValue); } });
2.實(shí)際工作中會(huì)使用哪種方案?
不同的業(yè)務(wù)系統(tǒng),會(huì)采用不同的解決方案,例如以下這些場(chǎng)景和對(duì)應(yīng)的解決方案:
- 如果對(duì)數(shù)據(jù)一致性要求不是很高,并且程序的并發(fā)壓力不大的情況下,可能使用方案 1,也就是設(shè)置本地緩存短時(shí)間內(nèi)失效的解決方案,因?yàn)樗膶?shí)現(xiàn)最簡(jiǎn)單。
- 如果對(duì)數(shù)據(jù)的一致性要求極高,且有配置中心的情況下,可使用配置中心協(xié)調(diào)和同步本地緩存。
- 相反,如果對(duì)一致性要求沒有那么高,且為高并發(fā)的系統(tǒng),那么可以采用本地緩存的自動(dòng)更新功能來實(shí)現(xiàn)。
小結(jié)
在多級(jí)緩存中,本地緩存是不可或缺的組成部分,而想要保證本地緩存的數(shù)據(jù)一致性,可能采用:設(shè)置較短的本地緩存過期時(shí)間、通過配置中心來協(xié)調(diào)和同步本地緩存,以及使用本地緩存框架的自動(dòng)更新功能保證數(shù)據(jù)的一致性等解決方案,而不同的業(yè)務(wù)場(chǎng)景,選擇的解決方案也是不同的。
以上就是詳解如何保證Java本地緩存的一致性的詳細(xì)內(nèi)容,更多關(guān)于Java本地緩存的一致性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Cloud Admin健康檢查 郵件、釘釘群通知的實(shí)現(xiàn)
這篇文章主要介紹了Spring Cloud Admin健康檢查 郵件、釘釘群通知的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08Java pom.xml parent引用報(bào)錯(cuò)問題解決方案
這篇文章主要介紹了Java pom.xml parent引用報(bào)錯(cuò)問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08java調(diào)用python代碼的兩種實(shí)現(xiàn)方式:Runtime.exec()和Jython
在Java中調(diào)用Python代碼有多種方法,包括使用Runtime.exec()和第三方庫如Jython,Runtime.exec()通過系統(tǒng)命令執(zhí)行Python腳本,適用于簡(jiǎn)單的調(diào)用場(chǎng)景,Jython則是一個(gè)Python的Java實(shí)現(xiàn),允許在Java中直接運(yùn)行Python代碼,適用于更深層次的集成需求2025-01-01SpringBoot 在測(cè)試時(shí)如何指定包的掃描范圍
這篇文章主要介紹了SpringBoot 在測(cè)試時(shí)如何指定包的掃描范圍,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11