Mysql和Redis數據同步策略

目錄

  • 為什麼對緩存只刪除不更新
  • 先更新數據庫還是先刪除緩存?
  • Cache Aside Pattern
  • Double-Delete
  • Read/Write Through Pattern
  • Write Behind
  • 設置緩存過期時間
  • 總結

為什麼對緩存只刪除不更新

不更新緩存是防止併發更新導致的數據不一致。
所以為了降低數據不一致的概率,不應該更新緩存,而是直接將其刪除,
然後等待下次發生cache miss時再把數據庫中的數據同步到緩存。

先更新數據庫還是先刪除緩存?

有兩個選擇:
1. 先刪除緩存,再更新數據庫
2. 先更新數據庫,再刪除緩存

如果先刪除緩存,有一個明顯的邏輯錯誤:考慮兩個併發操作,線程A刪除緩存后,線程B讀該數據時會發生Cache Miss,然後從數據庫中讀出該數據並同步到緩存中,此時線程A更新了數據庫。
結果導致,緩存中是老數據,數據庫中是新數據,並且之後的讀操作都會直接讀取緩存中的臟數據。(直到key過期被刪除或者被LRU策略踢出)
如果數據庫更新成功后,再刪除緩存,就不會有上面這個問題。
可能是由於數據庫優先,第二種方式也被稱為Cache Aside Pattern。

Cache Aside Pattern

cache aside在絕大多數情況下能做到數據一致性,但是在極端情況仍然存在問題。

  • 首先更新數據庫(A)和刪除緩存(B)不是原子操作,任何在A之後B之前的讀操作,都會讀到redis中的舊數據。
    正常情況下操作緩存的速度會很快,通常是毫秒級,臟數據存在的時間極端。
    但是,對超高併發的應用可能會在意這幾毫秒。
  • 更新完數據庫后,線程意外被kill掉(真的很不幸),由於沒有刪除緩存,緩存中的臟數據會一直存在。
  • 線程A讀數據時cache miss,從Mysql中查詢到數據,還沒來得及同步到redis中,
    此時線程B更新了數據庫並把Redis中的舊值刪除。隨後,線程A把之前查到的數據同步到了Redis。
    顯然,此時redis中的是臟數據。
    通常數據庫讀操作比寫操作快很多,所以除非線程A在同步redis前意外卡住了,否則發生上述情況的概率極低。

雖然以上情況都有可能發生,但是發生的概率相比“先刪除緩存再更新數據庫”會低很多。

Double-Delete

前面我們講到先刪除緩存(A)、后更新數據庫(B)的方案有明顯的錯誤,任何發生在A操作和B操作之間的併發讀都會造成數據的最終不一致。
Double-Delete是一種比較笨拙的修補方案,執行過程如下:

1.delete redis cache
2.update database
3.sleep(500ms)
3.delete redis cache

也很好理解,在睡眠500ms后嘗試再次刪除緩存中的臟數據,它通過兩次刪除來盡可能做到數據的最終一致。
其實,Double-Delete在數據一致性上比Cache Aside更靠譜,但是它的代價是昂貴的,
即使,把睡眠時間縮短到100ms,對耗時敏感的應用也不會考慮這種方案。

Read/Write Through Pattern

cache aside是我們自己的應用程序維護兩個數據存儲系統,而Read/Write Through Pattern是把同步數據的問題交給緩存系統了,應用程序不需要關心。
Read Through是指發生cache miss時,緩存系統自動去數據庫加載數據。
Write Through是指如果cache miss,直接更新數據庫,然後返回,如果cache hit,則更新緩存后,由緩存系統自動同步到數據庫。
以Redis為例,通常我們不會把數據庫的數據全部緩存到redis,而是採用一定的數據精簡或壓縮策略,以節省緩存空間。
就是說,讓緩存系統設計出通用的緩存方案不太現實,不過根據自己的業務定製一個在項目內部通用的中間件是可行的。

Write Behind

Write Behind方案在更新數據時,只更新緩存,不更新數據庫。而是由另外一個服務異步的把數據更新到數據庫。
邏輯上,和Linux中的write back很類似。這個設計的好處是,I/O操作很快,因為是純內存操作。
但是由於異步寫庫,可能要犧牲一些數據一致性,譬如突然宕機會丟失所有未寫入數據庫的內存數據。

阿里巴巴的Canal中間件是一種相反的設計,它先更新mysql,然後通過binlog把數據自動同步到redis。
這種方案會全量同步數據到redis,不適合只緩存熱點數據的應用。

設置緩存過期時間

無論採用哪種策略都應該設置緩存的過期時間。
過期時間設置太長,臟數據存在的時間就越長;
過期時間設置太短,大量的cache miss會讓查詢直接進入數據庫。
所以,需要根據業務場景考慮過期時間。

總結

以上沒有哪種方案是完美的,都無法做到強一致性。
我們總要在性能和數據準確性之間做出妥協。
Cache Aside Pattern適用於絕大多數的場景。

https://www.pixelstech.net/article/1562504974-Consistency-between-Redis-Cache-and-SQL-Database
https://coolshell.cn/articles/17416.html
為什麼不更新緩存,而是直接刪除

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

您可能也會喜歡…