緩存數據一致性 - 架構師峯會演講實錄

Previously

緩存系統涉及的問題和知識點是比較多的,我主要分爲如下幾個方面來跟你們探討:git

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

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

本文做爲系列文章第二篇,主要跟你們探討『緩存數據一致性』數據庫

緩存正確性

上篇文章提到,咱們引入緩存的初衷是爲了減少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架構師峯會-海量併發下的緩存架構設計

項目地址

https://github.com/tal-tech/go-zero

歡迎使用 go-zero 並 star 支持咱們!

微信交流羣

關注『微服務實踐』公衆號並點擊 進羣 獲取社區羣二維碼。

go-zero 系列文章見『微服務實踐』公衆號
相關文章
相關標籤/搜索