Mysql和Redis資料如何保持一致

京東雲發表於2022-08-23

先闡明一下Mysql和Redis的關係:Mysql是資料庫,用來持久化資料,一定程度上保證資料的可靠性;Redis是用來當快取,用來提升資料訪問的效能。


關於如何保證Mysql和Redis中的資料一致(即快取一致性問題),這是一個非常經典的問題。



使用過快取的人都應該知道,在實際應用場景中,要想實時刻保證快取和資料庫中的資料一樣,很難做到。



基本上都是儘可能讓他們的資料在絕大部分時間內保持一致,並保證最終是一致的。



快取不一致是如何產生的



如果資料一直沒有變更,那麼就不會出現快取不一致的問題。



通常快取不一致是發生在資料有變更的時候。 因為每次資料變更你需要同時運算元據庫和快取,而他們又屬於不同的系統,無法做到同時操作成功或失敗,總會有一個時間差。在併發讀寫的時候可能就會出現快取不一致的問題(理論上透過分散式事務可以保證這一點,不過實際上基本上很少有人這麼做)。



雖然沒辦法在資料有變更時,保證快取和資料庫強一致,但對快取的更新還是有一定設計方法的,遵循這些設計方法,能夠讓這個不一致的影響時間和影響範圍最小化。



快取更新的幾種設計



快取更新的設計方法大概有以下四種:



  • 先刪除快取,再更新資料庫(這種方法在併發下最容易出現長時間的髒資料,不可取)



  • 先更新資料庫,刪除快取(Cache Aside Pattern)



  • 只更新快取,由快取自己同步更新資料庫(Read/Write Through Pattern)



  • 只更新快取,由快取自己非同步更新資料庫(Write Behind Cache Pattern)



接下來詳細介紹一些這四種設計方法



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



這種方法在併發讀寫的情況下容易出現快取不一致的問題


Mysql和Redis資料如何保持一致


如上圖所示,其可能的執行流程順序為:



  • 客戶端1 觸發更新資料A的邏輯



  • 客戶端2 觸發查詢資料A的邏輯



  • 客戶端1 刪除快取中資料A



  • 客戶端2 查詢快取中資料A,未命中



  • 客戶端2 從資料庫查詢資料A,並更新到快取中



  • 客戶端1 更新資料庫中資料A



可見,最後快取中的資料A跟資料庫中的資料A是不一致的,快取中的資料A是舊的髒資料。



因此一般不建議使用這種方式。



先更新資料庫,再讓快取失效



這種方法在併發讀寫的情況下,也可能會出現短暫快取不一致的問題


Mysql和Redis資料如何保持一致


如上圖所示,其可能執行的流程順序為:



  • 客戶端1 觸發更新資料A的邏輯



  • 客戶端2 觸發查詢資料A的邏輯



  • 客戶端3 觸發查詢資料A的邏輯



  • 客戶端1 更新資料庫中資料A



  • 客戶端2 查詢快取中資料A,命中返回(舊資料)



  • 客戶端1 讓快取中資料A失效



  • 客戶端3 查詢快取中資料A,未命中



  • 客戶端3 查詢資料庫中資料A,並更新到快取中



可見,最後快取中的資料A和資料庫中的資料A是一致的,理論上可能會出現一小段時間資料不一致,不過這種機率也比較低,大部分的業務也不會有太大的問題。



只更新快取,由快取自己同步更新資料庫(Read/Write Through Pattern)



這種方法相當於是業務只更新快取,再由快取去同步更新資料庫。 一個Write Through的 例子如下:


Mysql和Redis資料如何保持一致


如上圖所示,其可能執行的流程順序為:



  • 客戶端1 觸發更新資料A的邏輯



  • 客戶端2 觸發查詢資料A的邏輯



  • 客戶端1 更新快取中資料A,快取同步更新資料庫中資料A,再返回結果

  • 客戶端2 查詢快取中資料A,命中返回



Read Through 和 WriteThrough 的流程類似,只是在客戶端查詢資料A時,如果快取中資料A失效了(過期或被驅逐淘汰),則快取會同步去資料庫中查詢資料A,並快取起來,再返回給客戶端



這種方式快取不一致的機率極低,只不過需要對快取進行專門的改造。



只更新快取,由快取自己非同步更新資料庫(Write Behind Cache Pattern)



這種方式性詳單于是業務只操作更新快取,再由快取非同步去更新資料庫,例如:


Mysql和Redis資料如何保持一致


如上圖所示,其可能的執行流程順序為:



  • 客戶端1 觸發更新資料A的邏輯



  • 客戶端2 觸發查詢資料A的邏輯



  • 客戶端1 更新快取中的資料A,返回



  • 客戶端2 查詢快取中的資料A,命中返回



  • 快取非同步更新資料A到資料庫中



這種方式的優勢是讀寫的效能都非常好,基本上只要操作完記憶體後就返回給客戶端了,但是其是非強一致性,存在丟失資料的情況。



如果在快取非同步將資料更新到資料庫中時,快取服務掛了,此時未更新到資料庫中的資料就丟失了。



總結



上面講到的幾種快取更新的設計方式,都是前人總結出來的經驗,這些方式或多或少都有一些弊端,並不完美,實際上也很難有完美的設計。 大家在做系統設計的時候,也不要去追求完美,要有一些取捨,找到一種最適合自己業務場景的方式就行



作者:追光者


相關文章