緩存和 DB 的數據一致性問題

緩存和DB的數據不一致主要有兩種情況:

  1. 併發的場景下,導致讀取舊的 DB 數據,更新到緩存中。
  2. 緩存和 DB 的操作,不在一個事務中,可能只有一個操作成功,而另一個操作失敗,導致不一致。

常用的優化方案,主要是解決兩個問題:

  1. 將緩存可能存在的並行寫,實現串行寫。
  2. 實現數據的最終一致性。

下面是我們比較常用到的集中優化手段:

1、先淘汰緩存,再寫數據庫,注意要引入分佈式鎖,從而實現串行寫的目的。

  • 在寫請求時,先淘汰緩存之前,獲取該分佈式鎖。
  • 在讀請求時,發現緩存不存在時,先獲取分佈式鎖。

2、先寫數據庫,再更新緩存

這時候需要保證 DB 和緩存的操作在“同一個事務”中,從而實現最終一致性。

下面有兩種實現方式:

① 基於定時任務來實現

  • 首先,寫入數據庫。
  • 然後,在寫入數據庫所在的事務中,插入一條記錄到任務表。該記錄會存儲需要更新的緩存 key和 value。
  • 最後,定時任務每秒掃描任務表,更新到緩存中,之後刪除該記錄。

② 基於消息隊列來實現

  • 先寫入數據庫。
  • 然後,在發送帶有緩存key和value 的事務消息。比如阿里的 RocketMQ 就支持消息事務。
  • 最後,消費者消費該消息,更新到緩存中。

3、基於數據庫的 binlog 日誌

  • 數據直接寫入數據庫。
  • 數據庫更新binlog日誌(注意:數據庫要開啓binlog爲row模式,因爲canal讀取binlog日誌格式要求如此)。
  • 利用阿里的Canal中間件讀取binlog日誌。
  • Canal藉助於限流組件按頻率將數據發到MQ中。
  • 將MQ的數據更新到Redis緩存中。

       雖然這種方式實現了緩存與DB的一致性,但是需要引入多餘的第三方組件來實現,實際項目還是要根據具體的需求來確定是否使用該方案。在之前的做過的一個項目中,我們就是使用了mysql, canal, kafka, Elasticsearch, 實現了Elasticsearch與mysql之間的數據一致性。

參考:https://www.w3cschool.cn/architectroad/architectroad-consistency-of-cache-with-database.html

          https://www.w3cschool.cn/architectroad/architectroad-consistency-of-cache-with-master-and-slave-database.html

          https://www.w3cschool.cn/architectroad/architectroad-master-and-slave-database-architecture-optimization.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章