快取與資料庫一致性問題深度剖析

2022-06-14 19:24:09 字數 2890 閱讀 8082

背景

背景:在併發讀寫的時候,資料明明已經成功寫入資料庫之中,但是我們從快取中讀出的資料還是以前的舊資料,開始以為是瀏覽器快取的問題,清了瀏覽器快取之後還是沒有。那可能是資料還沒有同步到快取中,按照**邏輯這有點不太可能呀!雖然不可能,那我們還是等等看吧。等了一段時間之後,資料顯示的還是舊資料。還是不行,怎麼辦呢?網上搜尋了一番,發現這就是著名的資料庫與快取不一致的問題!

先插一點題外話,感覺我們這個地方的邏輯有點不符合軟體的設計原則,因為快取的問題已經影響到了我們的業務系統,而處理快取的邏輯也耦合到了我們的**之中,一旦快取出現了問題,必須要通過修改我們的業務**才能解決問題,所以如何解決這個問題也是乙個難題,帶著這個問題我們繼續往下看。

快取的利與弊

既然說到了快取,那就先聊一下什麼樣的資料適合用快取,快取的利與弊。

快取適合量大但又不常變化的資料。對於那些經常變化的資料,其實並不適合快取,一方面會增加系統的複雜性(快取的更新,快取髒資料),另一方面也給系統帶來一定的不穩定性(快取系統的維護)。

上快取的優點:

- 能夠縮短服務的響應時間,給使用者帶來更好的體驗。

- 能夠增大系統的吞吐量,依然能夠提公升使用者體驗。

- 減輕資料庫的壓力,防止高峰期資料庫被壓垮,導致整個線上服務垮掉。

上快取的缺點:

- 快取系統也要考慮分布式,比如redis的分布式快取還會有很多坑,無疑增加了系統的複雜性。

- 在特殊場景下,如果對快取的準確性有非常高的要求,就必須考慮快取和資料庫的一致性問題。

如何保證快取和資料庫一致性

下面我們就討論一下如何保證資料庫與快取的一致性問題,以前一直覺得快取是乙個很簡單的東西,就是為了減少資料庫的訪問量,可當遇到這個問題之後,這個感覺就煙消雲散了。因為保證資料庫和快取的一致性是乙個亙古難題。因為在分布式系統中,根據cap理論,一致性,可用性,和分割槽容錯性是不可能同時滿足的,雖然cap說的是分布式,並不是資料庫和快取的問題。但是個人覺得還是可以套用一下cap的知識的。

網上搜尋很多資料,大部分觀點認為,做快取不應該是去更新快取,而是應該刪除快取,然後由下個請求去快取,發現不存在後再讀取資料庫,寫入快取。

下面分析為什麼是刪除快取而不是更新快取,

1:執行緒安全角度

試想,若同時有請求a和請求b進行更新操作,那麼會出現

(1)執行緒a更新了資料庫

(2)執行緒b更新了資料庫

(3)執行緒b更新了快取

(4)執行緒a更新了快取

這就導致了髒資料,因此不考慮。

2:業務場景角度

如果業務場景是度很頻繁的場景,但是讀的操作不是那麼的頻繁,就會導致每次更新資料庫都會更新快取,而快取並沒有沒讀去,造成了效能的浪費。(雖然這種場景並不會使用推薦使用快取,哈哈哈。)

那麼不更新快取,刪除快取就不會出現上面的問題了嗎?並不是這樣的,那麼是該先操作快取,還是該先運算元據庫呢?

下面我們就分析一下兩種場景,1:先刪除快取,在更新資料庫。2:先更新資料庫,在刪除快取。

1:先刪除快取,在更新資料庫

試想一下,若同時有乙個請求a進行更新操作,另乙個請求b進行查詢操作。則可能會出現:

(1)請求a進行寫操作,刪除快取

(2)請求b查詢發現快取不存在

(3)請求b去資料庫查詢得到舊值

(4)請求b將舊值寫入快取

(5)請求a將新值寫入資料庫

那麼將會造成髒資料,如果沒有設定快取資料的過期時間,那麼髒資料會一直在快取中。

2:先更新資料庫,在刪除快取

試想一下,若同時有兩個請求,乙個請求a做查詢操作,乙個請求b做更新操作,則可能會出現:

(1)快取剛好失效

(2)請求a查詢資料庫,得乙個舊值

(3)請求b將新值寫入資料庫

(4)請求b刪除快取

(5)請求a將查到的舊值寫入快取

可見,此方式依舊不能保證資料庫與快取的一致性。但是發生這種情況的前提是操作(3)比操作(2)更快,但是一般情況下資料庫的寫操作都是比讀的操作慢的,發生這種情況的概率很低。

那麼就沒有一種方案保持快取與資料庫的一致性了嗎?有當然是有的,參閱網上的很多資料之後發現了延時雙刪策略,這種方案總共有三步,

1:先刪除快取

2:更新資料庫

3:休眠一段時間(具體時間多長,是業務邏輯耗時而定),再次刪除快取(如果刪除失敗,重試再次刪除)。

如果使用讀寫分離架構會不會出現資料庫與快取不一致呢?答案是可能的?讓我們來看一下原因。

試想一下,還是兩個請求,乙個請求a進行更新操作,另乙個請求b進行查詢操作。

(1)請求a進行寫操作,刪除快取

(2)請求a將資料寫入資料庫了,

(3)請求b查詢快取發現,快取沒有值

(4)請求b去從庫查詢,這時,還沒有完成主從同步,因此查詢到的是舊值

(5)請求b將舊值寫入快取

(6)資料庫完成主從同步,從庫變為新值

大佬的方案是:業務邏輯無需對快取做任何操作,只需要做正常的資料庫操作即可。然後我們啟動乙個訂閱程式去訂閱資料庫的binlog,獲得需要操作的資料。在應用程式中,另起一段程式,獲得這個訂閱程式傳來的資訊,進行刪除快取操作,這個方案不僅解決了資料庫快取不一致的問題,也解決了我們題外話中的問題,可謂一舉兩得。

這裡附上大佬的流程圖:

上述的訂閱binlog程式在mysql中有現成的中介軟體叫canal,可以完成訂閱binlog日誌的功能。至於oracle中,博主目前不知道有沒有現成中介軟體可以使用。

總結:本文其實是對目前博主了解的資料庫與快取一致性方案做了乙個總結,至於大家選擇哪種方案,要根據系統的需求而定,避免對系統的架構過度設計,切不可認為最複雜的就是最好的,只有適合自己的才是最好的,最後,希望大家有所收穫。

快取與資料庫一致性問題

業務場景 抓拍到的人臉需要推送到第三方系統,但不是所有的網點都需要推送資訊。也就是要做到不同的網點可以根據配置來決定是否推送,前端頁面需要有推送配置功能,手動配置後,把配置的推送資訊儲存到資料庫。抓拍到人臉 後,讀取配置的推送資訊,再判斷是否需要推送。由於網點多抓拍的人臉資料量較大,推送資訊配置後不...

redis快取與資料庫一致性問題

不一致產生的原因 我們在使用redis過程中,通常會這樣做 先讀取快取,如果快取不存在,則讀取資料庫。偽 如下 object stuobj new object public stu getstufromcache string key return stu 寫資料庫的偽 如下 public voi...

資料庫和快取一致性問題

前言 快取一致性是指業務在引入分布式快取系統後,業務對資料的更新除了要更新儲存以外還需要同時更新快取,對兩個系統進行資料更新就要先解決分布式系統中的隔離性和原子性難題。目前大多數業務在引入分布式快取後都是通過犧牲小概率的一致性來保障業務效能,因為要在業務層嚴格保障資料的一致性,代價非常高,業務引入分...