快取與資料庫更新策略

2021-10-11 04:07:23 字數 1574 閱讀 2684

快取(redis、memory cache等)被廣泛應用於高併發、高效能的專案中。應用在,請求先查詢快取,命中則返回。未命中則查詢資料庫,並快取。而且快取也有過期時間的,避免浪費記憶體、出現不一致等,因此快取是最終一致性的。但實際使用中,需要主動更新快取。那就存在乙個問題:為保證資料讀取的正確性、一致性,是先更新快取,還是先更新資料庫?

資料變化時,快取可以更新也可以刪除,等查詢的時候再次快取即可。因此可以組合出以下四種策略:

先更新快取,再更新資料庫;

先刪除快取,再更新資料庫;

先更新資料庫,再更新快取;

先更新資料庫,再刪除快取;

上述策略都是兩步操作完成。下邊依次來分析這四種策略的可行性。

兩步:第一步更新快取,第二步更新資料庫。

場景1.執行緒a 嘗試更新資料庫,第一步更新快取

2.執行緒b 嘗試更新資料庫,第一步更新快取

3.執行緒b 第二步更新資料庫

4.執行緒a 第二步更新資料庫

場景1.執行緒a 嘗試更新資料庫,第一步更新快取

2.執行緒b 讀快取,未命中,繼續讀資料庫,並快取。(此時快取的是舊資料)

3.執行緒a 第二步更新資料庫

此時,在乙個ttl 內,快取內的資料是舊資料。出現了資料不一致。

場景1.執行緒a 嘗試更新資料庫,第一步 更新資料庫

2.執行緒b 嘗試更新資料庫,第一步 更新資料庫

3.執行緒a 第二步更新快取

4.執行緒a 第二步更新快取

此時,也是 a-b-b-a 的問題,導致快取中是執行緒a 設定的資料。在乙個ttl內,資料不一致。

接下來看先更新資料庫,再刪除快取。

這個也就是老外提出的《cache-aside pattern》。

場景1.執行緒a 嘗試 更新資料庫,第一步 更新資料庫,第二步刪除快取

2.執行緒b 嘗試 讀取 快取,未命中,讀取資料庫,並快取

此時,資料一致。這個在網上的facebook的**《scaling memcache at facebook》也是選擇這種策略

可能有人有疑問了:不會併發麼?確實存在的:

場景前提:快取中無資料

1.執行緒a 嘗試讀取,未命中快取,讀資料庫

2.執行緒b 嘗試 更新資料庫

3.執行緒b 刪除快取

4.執行緒a 把讀取的資料更新到快取

此時,也是 a-b-b-a 的問題。

確實,不過這裡需要說明一下:這種情況發生的概率比較低!!!

我們常用的資料庫mysql,包括oracle,更新操作耗時比較長,查詢操作耗時比較短。如果要達到,需要滿足 步驟1 的耗時比 步驟2+步驟3 的耗時長。這幾乎不可能的。執行緒a在 步驟1和步驟4之間做了其他事情。那就是邏輯問題了。我們實際使用中,採用這種策略就能滿足需要了。

可能有人要問了:

上述併發問題有辦法解決麼

有:可以採用非同步延時刪除策略,此時在 更新完資料庫 到 刪除快取這段時間,資料可能稍微不一致。

有其他可能情況不一致麼?

有:更新快取失敗!

方案:訊息重試,可以接dts訊息(binlog),這樣快取刪除失敗後,可以訊息重試。

快取更新策略

一般來說,快取有以下三種模式 cache aside更新模式 這種策略下,在併發寫的時候可能會出現髒資料的問題。read write through 更新模式 在read write through 更新模式中,應用程式只需要維護快取,資料庫的維護工作由快取 了。read through 模式就是在...

快取更新策略初探

這裡為什麼不讓更新操作在寫完資料庫之後,緊接著去把快取cache中的資料也修改了呢?主要是因為這樣做的話,就有2個寫操作的事件了,擔心在併發的情況下會導致髒資料,舉個例子 那麼 cache aside 模式就沒有髒資料問題了嗎?不是的,在極端情況下也可能會產生髒資料,比如 不過這種概率比上面一種概率...

Mysql 之 快取更新策略

業務角度,對於讀操作很少的,造成效能浪費 執行緒安全角度,容易產生資料髒讀 執行緒a更新了資料庫,執行緒b更新了資料庫,b更新了快取,a更新了快取 錯誤情況 請求a進行寫操作,刪除快取 請求b查詢發現快取不存在,讀取資料庫,寫入快取 請求a將資料寫入資料庫 解決方法 採用延時雙刪除法 在a寫入資料庫...