快取一致性

CloverYou發表於2022-01-06

快取資料的一致性

讀所有的資料,首先去快取中獲取,快取中沒有就去讀資料庫,最後在快取中放一份。如果該資料在資料庫中發生改變,那麼快取裡面的資料如何和資料庫保持一致?解決這個問題,目前有兩個用的非常多的場景:

  • 雙寫模式
  • 失效模式

雙寫模式

修改資料庫的資料後再修改快取中的資料

雙寫模式

但又引出了一個問題,那就是當有併發時,執行緒一將資料庫的值改為「一號」然後立刻將這個值儲存到快取,而儲存過程中遇到了種種原因,如網路波動,導致了資料延遲抵達快取伺服器,而此時執行緒二已經將資料庫資料改為「二號」然後將資料儲存到快取,執行緒二網路通暢,很快就抵達快取伺服器先於執行緒一將資料儲存到快取中,而此時執行緒一的資料才抵達快取伺服器,將資料「一號」儲存到了快取中(把二號覆蓋),這時快取中儲存的就是一個髒資料。

髒資料被儲存原理圖

這是臨時性的髒資料問題,但是在資料穩定、快取過期後,又能得到最新的正確資料。

讀到的最新資料有延遲,這就導致了資料的最終一致性問題。

失效模式

在改完資料庫後,將快取中的資料刪除,下一次請求進來從快取獲取資料時發現沒有對應資料,他會到資料庫中查詢並將資料儲存在快取中。

失效模式

失效模式也有資料最終一致性問題,例如有三臺伺服器同時併發,伺服器一負載小,修改資料庫和刪除快取一氣呵成,伺服器二負載大,在修改資料庫時磨磨蹭蹭耗時很久,而伺服器三是獲取資料的,他讀取快取沒有資料又去資料庫中將資料查出來了,此時查詢的是伺服器一修改的資料。完成這些操作後伺服器二才將資料庫修改瞬間刪除快取,而伺服器三在更新快取時遇到網路波動,非常久後才成功將資料儲存到快取中,但他儲存的卻是伺服器一修改的舊資料

髒資料被儲存原理圖

加鎖

以上兩種模式遇到的問題(亂序)都可以通過加鎖來解決,但是加鎖後系統可能會變得笨重,所以,如果我們的資料經常修改,那麼我們還需要將其放到快取中咩?

如果資料經常修改,那麼我們的鎖會經常在,會導致整個系統非常緩慢,如果我們想要實時的讀取,資料一致性要求非常高,那麼這種情況還不如不加鎖,直接訪問資料庫。

解決方案

  • 我們發現無論是雙寫模式還是失效模式,都會導致快取的的不一致問題。即多個例項同時更新就會出現問題,應該怎麼辦?
    1. 如果是使用者緯度資料(訂單資料,使用者資料),這種併發機率非常小,那麼就不需要考慮這個問題,快取資料加上過期時間,每隔一段時間觸發讀的主動更新即可。
    2. 如果是選單,商品介紹等基礎資料,也可以去使用 canal 訂閱 binlog 的方式。
    3. 快取資料 + 過期時間也足夠解決大部分業務對於快取的要求。
    4. 通過加鎖保證併發讀寫,寫寫的時候按順序排隊,讀讀則無所謂。所以適合使用讀寫鎖。(業務不關心臟資料,允許臨時髒資料可忽略)。

總結

  • 我們能放入快取的資料本就不應該是實時性、一致性要求超高的,所以快取資料的時候加上過期時間,保證每天拿到當前最新資料即可。
  • 我們不應該過度設計。增加系統的複雜性
  • 遇到實時性、一致性要求高的資料,就應該查資料庫,即使慢點,也無所謂。

歡迎訪問我的個人部落格
博文在部落格中的連結: https://www.ctong.top/index.php/archives/91

相關文章