快取資料一致性 - 架構師峰會演講實錄

kevwan發表於2021-05-16

Previously

快取系統涉及的問題和知識點是比較多的,我主要分為以下幾個方面來跟大家探討:

  • 穩定性
  • 正確性
  • 可觀測性
  • 規範落地和工具建設

上篇 我們分析了快取系統的穩定性,介紹了 go-zero 是怎麼解決快取穿透、快取擊穿、快取雪崩問題的。比較淺顯易懂,且具有比較強的實戰意義,推薦一讀。

本文作為系列文章第二篇,主要跟大家探討『快取資料一致性』

快取正確性

上篇文章提到,我們引入快取的初衷是為了減小DB壓力,增加系統穩定性,所以我們一開始關注的是快取系統的穩定性。當穩定性解決之後,一般我們就會面臨資料正確性問題,可能會經常遇到『明明資料更新了,為啥還是顯示老的呢?』這類問題。這就是我們常說的『快取資料一致性』問題了,接下來我們仔細下分析其產生的原因及應對方法。

資料更新常見做法

首先,我們講資料一致性的前提是我們DB的更新和快取的刪除不會當成一個原子操作來看待,因為在高併發的場景下,我們不可能引入一個分散式鎖來把這兩者繫結為一個原子操作,如果繫結的話就會很大程度上影響併發效能,而且增加系統複雜度,所以我們只會追求資料的最終一致性,且本文只針對非追求強一致性要求的高併發場景,金融支付等同學自行判斷。

常見資料更新方式有兩大類,其餘基本都是這兩類的變種:

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

這種做法是遇到資料更新,我們先去刪除快取,然後再去更新DB,如左圖。讓我們來看一下整個操作的流程:

  • A請求需要更新資料,先刪除對應的快取,還未更新DB
  • B請求來讀取資料
  • B請求看到快取裡沒有,就去讀取DB並將舊資料寫入快取(髒資料)
  • A請求更新DB

可以看到B請求將髒資料寫入了快取,如果這是一個讀多寫少的資料,可能髒資料會存在比較長的時間(要麼有後續更新,要麼等待快取過期),這是業務上不能接受的。

  • 先更新資料庫,再刪除快取

上圖的右側部分可以看到在A更新DB和刪除快取之間B請求會讀取到老資料,因為此時A操作還沒有完成,並且這種讀到老資料的時間是非常短的,可以滿足資料最終一致性要求。

上圖可以看到我們用的是刪除快取,而不是更新快取,原因如下圖:

上圖我用操作代替了刪除或更新,當我們做刪除操作時,A先刪還是B先刪沒有關係,因為後續讀取請求都會從DB載入出最新資料;但是當我們對快取做的是更新操作時,就會對A先更新快取還是B先更新快取敏感了,如果A後更新,那麼快取裡就又存在髒資料了,所以 go-zero 只使用刪除快取的方式。

我們來一起看看完整的請求處理流程:

注意:不同顏色代表不同請求。

  • 請求1更新DB
  • 請求2查詢同一個資料,返回了老的資料,這個短時間內返回舊資料是可以接受的,滿足最終一致性
  • 請求1刪除快取
  • 請求3再來請求時快取裡沒有,就會查詢資料庫,並回寫快取再返回結果
  • 後續的請求就會直接讀取快取了

另外留一個問題大家可以思考下,對於下圖的場景,我們該怎麼應對?

如果你有好的解決方法或者想知道怎麼解決,歡迎 go-zero 社群微信群內交流~~

未完待續

本文跟大家一起討論了快取資料一致性問題,下一篇我來跟大家一起討論快取系統的監控以及如何讓快取程式碼更規範、更少bug。

所有這些問題的解決方法都已包含在 go-zero 微服務框架裡,如果你想要更好的瞭解 go-zero 專案,歡迎前往官方網站上學習具體的示例。

視訊回放地址

ArchSummit架構師峰會-海量併發下的快取架構設計

專案地址

github.com/tal-tech/go-zero

歡迎使用 go-zero 並 star 支援我們!

微信交流群

關注『微服務實踐』公眾號並點選 進群 獲取社群群二維碼。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章