技能篇:關於快取資料的一致性探討

潛行前行發表於2021-11-15

為了更快響應請求,減少不必要的查詢,加速資料的處理,資料快取是我們日常開發繞不過去的環節

image.png

關注公眾號,一起交流,微信搜一搜: 潛行前行

快取的意義

資料的儲存,離不開磁碟或者記憶體的操作。為了永久性的儲存,資料最終還是會同步到磁碟上,小流量小併發的系統,直接使用 mysql 進行資料的操作即可滿足需求。但面對高併發大流量時,又應該怎麼去更新儲存讀取資料呢?使用記憶體作為緩衝區,即快取。CPU 操作記憶體空間的速度是比磁碟快一個大級別的,記憶體操作就是在公路上開汽車,磁碟讀寫則在小道上騎自行車

  • 基於記憶體去做快取,有兩種方案:一是基於本地記憶體實現,如簡單使用 HashMap,guava 的 LoadCache,Caffeine;二是依賴區域網中的其他中介軟體,如 redis,Memcache,SQLite。這些記憶體資料庫廣泛地被當做分散式快取中介軟體使用
  • 把資料攔截在記憶體上去操作,確實是提高了系統的效能。但是記憶體上的資料容易丟失,萬一停電,機器當機,資料全就沒了,而且記憶體的硬體貴,容量小,並不是一個儲存資料永久之地。因為我們最終還是要把資料同步到磁碟DB上,而同步就會出現一致性的問題

快取的不一致性

  • 讀一致性:先讀取快取資料,有資料則直接返回;如果讀取不到,則讀取BD上的資料,然後給快取的資料設定過期時間,避免資料永久停留在記憶體上。讀一致性問題不大
  • 寫一致性:這裡的寫是專指新增的操作。和讀操作差不多,直接寫入資料庫即可,如果後續有讀操作,則使用讀一致性的操作步驟即可保證一致性
  • 更新一致性:更新操作則有點麻煩,有兩個問題:一是先更新快取呢,還是刪除快取?二是先操作快取還是 DB ? 兩個問題組合起來就有四種方案了,各位帶著問題往下看

先更新快取後更新BD

這個方案基本不可能會被採用的,因為出了問題是不可挽回的。想一想在多執行緒操作的情況下
image.png

為啥說這個方案不會被採用呢?設想使用者下單的場景。第一步:更新快取裡下單狀態為成功(假設此時會預定庫存);第二步讀取到下單成功狀態,然後準備去支付(此時第三步更新DB失敗了)

  • 假設支付階段,讀取到快取裡的下單狀態為成功,最終支付完成。因為下單階段會預定庫存,但實際 DB 更新失敗,這將導致超賣。收了錢卻沒貨發,等著被起訴吧,或者賠償使用者
  • 假設支付階段,剛好快取失效,讀取到 DB 裡的真實下單狀態,支付失敗。給使用者的感覺就是垃圾產品

先更新DB後更新快取

先更新資料庫後更新快取同樣會存在資料不一致性,請看以下場景
image.png
網路問題可能會導致執行緒B更新快取比執行緒A更快,而在第四步完成之後,快取失效之前,快取和資料庫就會存在不一致性問題

  • 將更新DB和更新快取操作封裝在同一個事務?雖然可以做到強一致性,但這導致資料庫事務的延長,會導致服務效能下降,本來引入快取是為加大效能,怎麼反向操作了
  • 可能你會認為不一致只是短暫的,可以接受,資料最終還是會達成一致性的。但是下面還有更好的方案為啥要選這個呢?
  • 還有如果寫操作多,讀操作少,這種方案就會導致,資料壓根還沒讀到,快取就被頻繁的更新,浪費系統資源
  • 還有些場景,資料是要經過複雜的計算才寫入快取的,而並非寫入資料庫的那個資料。在讀少寫多的業務,這多出的計算操作也是浪費系統資源的

先刪快取後更新DB

看一下先刪快取後更新DB方案
image.png

  • 這個方案比更新DB後更新快取好的地方在於,不用事先計算快取,更新快取
  • 但在第四步操作後,先刪快取後更新DB一樣存在短暫的不一致性,怎麼辦?可以採用 延遲雙刪方案

延遲雙刪方案

image.png
可以看到延遲雙刪方案增加了一步驟,在更新完資料之後,延遲一段時間再刪除快取。至於這幾毫秒怎麼確定,則需要同學們自己根據相應服務資料的讀操作耗時時間確定。延遲刪除時間 = 讀操作耗時時間 + 浮動時間(大概幾十毫秒就行)

  • 延遲雙刪方案不能完美做到杜絕 快取和DB不一致現象發生,只是極大概率減少資料不一致

先更新DB後刪快取

image.png
該方案也是不能完美解決不了資料的不一致性,但同樣可以延遲刪除的策略來降低資料不一致性的發生概率

  • 對比先刪快取後更新DB方案,優化的點在於少了一次刪除操作

延遲刪除

image.png

刪除失敗,怎麼補救

延遲刪除,會不會存在刪除失敗的情況呢,這時怎麼辦。可以採用下面兩種策略來補救

  • 刪除快取重試機制
    image.png
  • 讀取biglog非同步刪除快取
    • 刪除快取重試機制有一個缺點,對業務線程式碼造成大量的侵入
    • 讀取biglog非同步刪除快取方案:專門啟動一個更新快取程式去訂閱資料庫的binlog,獲得需要操作的資料,然後在進行更新快取操作
      image.png

歡迎指正文中錯誤

參考文章

相關文章