天天看點

緩存和資料庫雙寫不一緻?怎麼解決?

解釋:連續寫資料庫和緩存,但是操作期間,出現并發了,資料不一緻了。

通常,更新緩存和資料庫有以下幾種順序:

l 先更新資料庫,再更新緩存。

l 先删緩存,再更新資料庫。

l 先更新資料庫,再删除緩存。

三種方式的優劣來看一下:

先更新資料庫,再更新緩存。

這麼做的問題是:當有 2 個請求同時更新資料,那麼如果不使用分布式鎖,将無法控制最後緩存的值到底是多少。也就是并發寫的時候有問題。

先删緩存,再更新資料庫。

這麼做的問題:如果在删除緩存後,有用戶端讀資料,将可能讀到舊資料,并有可能設定到緩存中,導緻緩存中的資料一直是老資料。

有 2 種解決方案:

l 使用“雙删”,即删更删,最後一步的删除作為異步操作,就是防止有用戶端讀取的時候設定了舊值。

l 使用隊列,當這個 key 不存在時,将其放入隊列,串行執行,必須等到更新資料庫完畢才能讀取資料。

總的來講,比較麻煩。

先更新資料庫,再删除緩存

這個實際是常用的方案,但是有很多人不知道,這裡介紹一下,這個叫 Cache Aside Pattern,老外發明的。如果先更新資料庫,再删除緩存,那麼就會出現更新資料庫之前有瞬間資料不是很及時。

同時,如果在更新之前,緩存剛好失效了,讀用戶端有可能讀到舊值,然後在寫用戶端删除結束後再次設定了舊值,非常巧合的情況。

有 2 個前提條件:緩存在寫之前的時候失效,同時,在寫客戶度删除操作結束後,放置舊資料 —— 也就是讀比寫慢。設定有的寫操作還會鎖表。

是以,這個很難出現,但是如果出現了怎麼辦?使用雙删!!!記錄更新期間有沒有用戶端讀資料庫,如果有,在更新完資料庫之後,執行延遲删除。

還有一種可能,如果執行更新資料庫,準備執行删除緩存時,服務挂了,執行删除失敗怎麼辦???

這就坑了!!!不過可以通過訂閱資料庫的 binlog 來删除。

參考

https://coolshell.cn/articles/17416.html https://www.cnblogs.com/rjzheng/p/9041659.html https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside