****欧欧美毛片4,国产午夜精品视频,97视频在线观看免费视频,久久七国产精品

數據恢復咨詢熱線:400-666-3702??

歡迎訪問南京兆柏數據恢復公司,專業數據恢復15年

兆柏數據恢復公司

?常見問題

?當前位置: 主頁 > 常見問題

緩存與數據庫不一致了,咋辦?

瀏覽量: 次 發布日期:2023-10-09 09:02:25

緩存與數據庫不一致了,咋辦?

正文

只要使用Redis緩存,就必然存在緩存和DB數據一致性問題。若數據不一致,則業務應用從緩存讀取的數據就不是最新數據,可能導致嚴重錯誤。如將商品庫存緩存在Redis,若庫存數量不對,則下單時就可能出錯,這是難以接受的。

一致性包含如下情況:

緩存有數據緩存的數據值需和DB相同

緩存無數據DB是最新值

不符合這兩種情況的,都屬于緩存和DB數據不一致。

根據是否接收寫請求,可將緩存分成讀寫緩存和只讀緩存。

若要對數據進行增刪改,需要在Cache進行。同時根據采取的寫回策略,決定是否同步寫回DB:

寫緩存時,也同步寫數據庫,緩存和數據庫中的數據一致。

寫緩存時不同步寫DB,等到數據從緩存中淘汰時,再寫回DB。使用這種策略時,若數據還沒有寫回DB,緩存就發生故障,則此時,DB就沒有最新數據了。

所以,對于讀寫緩存,要想保證緩存和DB數據一致,就要采用同步直寫。若采用這種策略,就需同時更新緩存和DB。所以,要在業務代碼中使用事務,保證緩存和DB更新的原子性,即兩者:

要么一起更新

要么都不更新,返回錯誤信息,進行重試

否則,我們無法實現同步直寫。

有些場景下,我們對數據一致性要求不高,比如緩存的是電商商品的非關鍵屬性或短視頻的創建或修改時間等,則可以使用異步寫回。

新增數據直接寫DB

刪改數據刪改DB,刪除只讀緩存中的數據

這樣應用后續再訪問這些增刪改的數據時,由于Cache無數據 =》緩存缺失。此時,再從DB把數據讀入Cache,這樣后續再訪問數據時,直接讀Cache。

下面我們針對只讀緩存,看看具體會遇到哪些問題,又該如何解決。

數據直接寫到DB,不操作Cache。此時,Cache本身無新增數據,而DB是最新值,所以,此時緩存和DB數據一致。

此時應用既要更新DB,也要刪除Cache。這倆操作若無法保證原子性,就可能出現數據不一致。

綜上,在更新DB和刪除Cache時,無論這倆操作誰先執行,只要有一個操作失敗了,就會導致客戶端讀到舊值。

那怎么辦?好像怎么都會導致數據不一致?

要刪除的Cache值

或要更新的DB值

暫存到MQ。

當應用刪除Cache或更新DB:

成功把這些值從MQ去除,避免重復操作,這時即可保證DB、Cache數據一致性。

失敗重試。從MQ重新讀取這些值,然后再次進行刪除或更新。若重試超過一定次數,還沒成功,就向業務層發送報錯信息。

在更新數據庫和刪除緩存值的過程中,其中一個操作失敗了:

若刪除緩存失敗,再次重試后刪除成功

其它情況不再贅述。

即使這兩個操作第一次執行時都沒有失敗,當有大量并發請求時,應用還是有可能讀到不一致的數據。按不同的刪除和更新順序,分成兩種情況來看

假設條件:

時刻t1< t2 < t3

線程 T1、T2

這咋辦?可以考慮如下解決方案:

T1更新完DB后,讓它sleep一段時間,再刪除Cache。

讓T2能先從DB讀數據,再把缺失數據寫入Cache,然后,T1再進行刪除。所以,T1 sleep的時間,就要大于T2讀取數據再寫入Cache的時間。

業務程序運行時,統計一下線程讀數據和寫緩存的操作時間,以此估算。確保讀請求結束,寫請求可刪除讀請求造成的緩存臟數據。

該策略還要考慮 Cache 和 DB 主從同步的耗時。最后寫數據的休眠時間:則在讀數據業務邏輯的耗時的基礎上,加上幾百ms即可。

這樣,當其它線程讀數據時,會發現Cache未命中,所以從DB讀最新值。因為該方案會在第一次刪除Cache后,延遲一段時間再刪除,所以叫“延遲雙刪”。

cache.delKey(X) db.update(X) Thread.sleep(N) cache.delKey(X)

設置緩存TTL,是保證最終一致性的解決方案。所有寫操作以DB為準,只要到達緩存TTL,則后面的讀請求自然都會從DB讀最新值,然后回填緩存。

結合【雙刪策略】+【緩存TTL設置】,這樣最差情況就是在TTL時間內數據存在不一致,而且又增加寫請求耗時。

操作完DB后,由于某原因刪除Cache失敗,此時可能出現數據不一致,需提供重試補償方案:

更新DB

Cache因某異常,刪除失敗(問題點)

將待刪除的K發送至MQ

自己消費消息,獲得待刪除K

重試刪除操作,直到成功(解決問題)

該方案有個缺點,對業務代碼侵入性太強,于是有方案二。方案二中,啟動一個訂閱程序去訂閱DB的binlog,獲得待操作的數據。在應用程序中,另起一段程序,獲得這個訂閱程序傳來的信息,執行刪除Cache操作。

更新DB數據

DB會將操作信息寫入binlog日志

訂閱程序提取出所需要的數據及K

另起一段非業務代碼,獲得該信息

嘗試刪除Cache操作,發現刪除失敗

將這些信息發送至MQ

重新從MQ獲得該數據,重試刪除操作

以上方案都是在業務中經常會碰到的場景,可據業務對數據一致性的要求選擇具體方案。

這種情況下,如果其他線程并發讀緩存的請求不多,那么,就不會有很多請求讀取到舊值。而且,線程A一般也會很快刪除緩存值,這樣一來,其他線程再次讀取時,就會發生緩存缺失,進而從數據庫中讀取最新值。所以,這種情況對業務的影響較小。

至此,Cache和DB數據不一致的原因也都有了對應解決方案。

刪除Cache或更新DB失敗而導致數據不一致重試,確保刪除或更新成功

在刪除Cache、更新DB這兩步操作中,有其他線程的并發讀操作,導致其他線程讀取到舊值延遲雙刪

絕大多數場景都會將Redis作為只讀緩存:

既可以先刪除緩存值再更新數據庫

也可以先更新數據庫再刪除緩存

推薦優先使用先更新數據庫再刪除緩存:

先刪除緩存值再更新數據庫,有可能導致請求因緩存缺失而訪問數據庫,給數據庫帶來壓力

如果業務應用中讀取數據庫和寫緩存的時間不好估算,那么,延遲雙刪中的等待時間就不好設置

不過,當使用先更新數據庫再刪除緩存時,也有個地方需要注意,如果業務層要求必須讀取一致的數據,那么,我們就需要在更新數據庫時,先在Redis緩存客戶端暫存并發讀請求,等數據庫更新完、緩存值刪除后,再讀取數據,從而保證數據一致性。

在只讀緩存中進行數據的刪改操作時,需要在緩存中刪除相應的緩存值。若此過程不是刪除緩存,而是直接更新緩存,效果如何?

這種情況相當于把Redis當做讀寫緩存使用,刪改操作同時操作DB、Cache。

若更新DB成功,但Cache更新失敗,此時DB最新值,但緩存舊值,后續讀請求會直接命中緩存,得到舊值。

上海數據恢復

如果更新緩存成功,但數據庫更新失敗:

緩存中是最新值

數據庫中是舊值

后續讀請求會直接命中緩存,但得到的是最新值,短期對業務影響不大。但一旦緩存過期或滿容后被淘汰,讀請求就會從數據庫中重新加載舊值到緩存中,之后的讀請求會從緩存中得到舊值,對業務產生影響。

針對這種其中一個操作可能失敗的情況,類似只讀緩存方案,也可使用重試。把第二步操作放入到MQ中,消費者從MQ取出消息,再更新緩存或數據庫,成功后把消息從消息隊列刪除,否則進行重試,以此達到數據庫和緩存的最終一致。

也會產生不一致,分為以下4種雙寫場景。

雙寫模式下,更新DB有返回值,更新Redis的操作可放到更新DB返回后進行,通過數據庫的行鎖機制,可以避免更新DB是線程A,B,但更新Redis是線程B,A的情況。

無錫數據恢復

寫+讀并發。線程A先更新數據庫,之后線程B讀取數據,此時線程B會命中緩存,讀取到舊值,之后線程A更新緩存成功,后續的讀請求會命中緩存得到最新值。

這時,線程A未更新完緩存之前,在這期間的讀請求會短暫讀到舊值,對業務短暫影響。

寫+讀并發。線程A先更新緩存成功,之后線程B讀取數據,此時線程B命中緩存,讀取到最新值后返回,之后線程A更新數據庫成功。這種場景下,雖然線程A還未更新完數據庫,數據庫會與緩存存在短暫不一致,但在這之前進來的讀請求都能直接命中緩存,獲取到最新值,所以對業務沒影響。

寫+寫并發。線程A和線程B同時更新同一條數據,更新數據庫的順序是先A后B,但更新緩存時順序是先B后A,這會導致數據庫和緩存的不一致。

寫+寫并發。與場景3類似,線程A和線程B同時更新同一條數據,更新緩存的順序是先A后B,但是更新數據庫的順序是先B后A,這也會導致數據庫和緩存的不一致。

場景1和2對業務影響較小,場景3和4會造成數據庫和緩存不一致,影響較大。即讀寫緩存下,寫+讀并發對業務的影響較小,而寫+寫并發時,會造成數據庫和緩存的不一致。

針對場景3、4解決方案:對于寫請求,配合分布式鎖。寫請求進來時,針對同一資源的修改操作,先加分布式鎖,這樣同一時間只允許一個線程去更新DB和Cache,沒有拿到鎖的線程把操作放入到MQ,延時處理。這樣保證多個線程操作同一資源的順序性,以此保證一致性。

綜上,使用讀寫緩存同時操作數據庫和緩存時,因為其中一個操作失敗導致不一致的問題,同樣可以通過MQ重試解決。而在并發的場景下,讀+寫并發對業務沒有影響或者影響較小,而寫+寫并發時需要配合分布式鎖的使用,才能保證緩存和數據庫的一致性。

另外,讀寫緩存模式由于會同時更新數據庫和緩存:

優點緩存一直會有數據。若更新后立即訪問,可直接命中緩存,能降低讀請求對DB的壓力(沒有只讀緩存的刪除緩存導致緩存缺失和再加載的過程)

缺點若更新后的數據,之后很少再被訪問到,會導致緩存中保留的不是最熱數據,緩存利用率不高(只讀緩存中保留的都是熱數據)

所以讀寫緩存比較適合用于讀寫相當的業務場景。

相關推薦