就是這麼應對面試官的快取與資料庫一致性問題?

寫程式碼的小楊發表於2021-07-20

在日常開發過程中,對於Redis和MySQL的使用想必是不陌生的。當面對一些較為簡單的使用場景時,貌似也不會很困難。但是在涉及到快取和資料庫之間的資料同步問題的時候,一個考慮不慎,也許就該準備簡歷了。今天小楊就和大家聊一聊這點。

大多數我們操作Redis的時候,一般的使用場景:1、寫少讀多,修改性較低的場景,2、或者儲存一些熱點的資料或者配置 ,從而緩解資料庫的壓力。但是,當我們將快取搭配資料庫一起使用到一些較為複雜的使用場景時,資料的一致性問題就顯得比較突出,尤其是在請求較多的情況下。接下來我們分析一些常見的方案,並分析其優缺點,供大家選擇。

首先對於快取,是刪除呢還是更新呢

對於快取,我覺得較為正確的做法是:先刪除快取,而不是更新。較為常見的做法:先刪除快取,當下一次請求查詢快取不在的時候,就去查資料庫,再將結果寫入快取。原因如下:

1、假如是寫比讀多的情況下,每次操作更新的時候會比較浪費效能,尤其是資料是經過一系列複雜計算或者操作的時候,尤為明顯。

2、當兩個執行緒通過更新資料庫再更新快取的時候,如果出現網路延遲或者卡頓等情況下,有可能會造成前後更新快取的順序不一樣,結果導致快取出現髒資料。

那是先刪除快取,再更新資料庫,還是先更新資料庫,再更新快取呢

對於先刪除快取,再更新資料庫這種情況,我們會發現存在資料不一致的情況。如:

  1. 當第一個請求進來的時候,先刪除了快取
  2. 此時第二個請求發現沒有快取,於是到資料庫去讀取並將資料寫入到快取中
  3. 第一個請求再將資料寫入到資料庫中

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

對於這種情況下,如果不是很嚴格的一致性的問題,可以採用這種方式,但是在一些高併發,依舊會存在一些問題,如下面這種例子:

  1. 在更新資料庫之前有查詢請求,並且剛好快取失效了,於是進行查詢了資料庫,得到資料
  2. 此時,發生了寫的操作請求,將新的值更新了資料庫並刪除了快取
  3. 第一個請求將值寫入快取 (此時的資料為舊的資料,也就是發生了資料不一致的情況)

基於上面的分析:為什麼還是可以得到推薦呢,原因在於,發生上面的情況的條件在於第一步的查詢資料庫會比第二部寫資料庫慢,才會發生先刪除再寫入的情況 這種情況相對較小。大部分資料庫做了讀寫分離的架構,讀的速度會相對寫更快。

快取延時雙刪

這個是最為推薦的方案,其方案是在第一種的基礎上進行改善優化,流程如下:

  1. 先刪除快取

  2. 再寫資料庫

  3. 休眠x秒,再刪除快取

這個休眠是為什麼呢,為了解決資料庫寫入時主從庫之間同步的時間差異,確保讀請求結束,寫請求可以刪除讀請求造成的快取髒資料。這個休眠的時間取決於專案讀資料業務邏輯的耗時

針對上面的延遲雙刪的情況,還可以進行一些優化:

1、針對第三步的刪除快取的可以進行非同步刪除,這樣的話就無需每次進行休眠,從而提高吞吐量,提高效能。

2、如果擔心刪除失敗的話,可以考慮新增重試機制,如:重新測試三次失敗後,如果還不行的話,可以再丟進佇列,等下次的重試。

歡迎下方交流討論。如果本篇部落格有任何錯誤,請批評指教,不勝感激 !

共同進步,學習分享

歡迎大家關注我的公眾號【寫程式碼的小楊】,相關文章、學習資料都會在裡面更新,整理的資料也會放在裡面。

覺得寫的還不錯的就點個贊,加個關注唄!持續更新 !!! 點關注,不迷路,小楊帶你上高速

相關文章