redis 快取和資料庫寫入不一致問題

2021-10-05 11:29:22 字數 1681 閱讀 2210

cap理論(cache aside pattern):快取+資料庫讀寫的模式

1.讀的時候,先讀快取,快取沒有的話,就讀資料庫,然後取出資料後放入快取,同時返回響應。

2.更新的時候,先更新資料庫,然後再刪除快取。

請求和寫請求序列化,串到乙個記憶體佇列裡去

序列化可以保證一定不會出現不一致的情況,但是它也會導致系統的吞吐量大幅度降低,用比正常情況下多幾倍的機器去支撐線上的乙個請求

原因很簡單,很多時候,在複雜點的快取場景,快取不單單是資料庫中直接取出來的值。

比如可能更新了某個表的乙個字段,然後其對應的快取,是需要查詢另外兩個表的資料並進行運算,才能計算出快取最新的值的。

另外更新快取的代價有時候是很高的。是不是說,每次修改資料庫的時候,都一定要將其對應的快取更新乙份?也許有的場景是這樣,但是對於比較複雜的快取資料計算的場景,就不是這樣了。如果你頻繁修改乙個快取涉及的多個表,快取也頻繁更新。但是問題在於,這個快取到底會不會被頻繁訪問到?

舉個栗子,乙個快取涉及的表的字段,在 1 分鐘內就修改了 20 次,或者是 100 次,那麼快取更新 20 次、100 次;但是這個快取在 1 分鐘內只被讀取了 1 次,有大量的冷資料。實際上,如果你只是刪除快取的話,那麼在 1 分鐘內,這個快取不過就重新計算一次而已,開銷大幅度降低。用到快取才去算快取。

其實刪除快取,而不是更新快取,就是乙個 lazy 計算的思想,不要每次都重新做複雜的計算,不管它會不會用到,而是讓它到需要被使用的時候再重新計算。像 mybatis,hibernate,都有懶載入思想。查詢乙個部門,部門帶了乙個員工的 list,沒有必要說每次查詢部門,都裡面的 1000 個員工的資料也同時查出來啊。80% 的情況,查這個部門,就只是要訪問這個部門的資訊就可以了。先查部門,同時要訪問裡面的員工,那麼這個時候只有在你要訪問裡面的員工的時候,才會去資料庫裡面查詢 1000 個員工。

資料發生了變更,先刪除了快取,然後要去修改資料庫,此時還沒修改。乙個請求過來,去讀快取,發現快取空了,去查詢資料庫,查到了修改前的舊資料,放到了快取中。隨後資料變更的程式完成了資料庫的修改。完了,資料庫和快取中的資料不一樣了

解決方案如下:

更新資料的時候,根據資料的唯一標識,將操作路由之後,傳送到乙個 jvm 內部佇列中。讀取資料的時候,如果發現資料不在快取中,那麼將重新讀取資料+更新快取的操作,根據唯一標識路由之後,也傳送同乙個 jvm 內部佇列中。

乙個佇列對應乙個工作執行緒,每個工作執行緒序列拿到對應的操作,然後一條一條的執行。這樣的話,乙個資料變更的操作,先刪除快取,然後再去更新資料庫,但是還沒完成更新。此時如果乙個讀請求過來,沒有讀到快取,那麼可以先將快取更新的請求傳送到佇列中,此時會在佇列中積壓,然後同步等待快取更新完成。

這裡有乙個優化點,乙個佇列中,其實多個更新快取請求串在一起是沒意義的,因此可以做過濾,如果發現佇列中已經有乙個更新快取的請求了,那麼就不用再放個更新請求操作進去了,直接等待前面的更新操作請求完成即可。

如果請求還在等待時間範圍內,不斷輪詢發現可以取到值了,那麼就直接返回;如果請求等待的時間超過一定時長,那麼這一次直接從資料庫中讀取當前的舊值。

高併發的場景下,該解決方案要注意的問題:

redis快取 資料庫雙寫不一致

讀的時候 先讀快取,快取沒有的話,再讀取資料庫,然後取出資料後放入快取,同時返回響應 更新的時候 先刪除快取,然後再更新資料庫 之所以刪除快取而不是更新,其實是乙個懶載入的思想,避免頻繁更新,降低開銷,同時也可以避免更新快取成功後在更新資料庫時異常帶來的問題 場景1 先修改資料庫,再修改 刪除快取,...

redis資料庫快取

使用redis作為快取,資料還需要存入資料庫中嗎?我的答案是 1redis只是快取,不是資料庫如mysql,所以redis中有的資料庫,mysql中一定有。2使用者請求先去請求redis,如果沒有,再去資料庫中去讀取。3redis中快取一些請求量比較大的資料 這些快取資料,mysql中一定也是有的 ...

Redis和資料庫快取一致性問題之我見

乙個經典的問題,redis經常被用來當作快取,那麼redis快取一致性怎麼解決?翻閱了網上很多資料,答案不一,這裡簡單整理一下我的看法。目錄2 先運算元據庫,後操作快取 2.2 先更新資料庫,再刪快取 3 個人總結 4 番外 從借鑑作業系統的一些方法 參考問題 髒寫 在併發的情況下,可能出現以下情況...