mysql cache一致性問題

https://blog.csdn.net/ly262173911/article/details/75127339

http://www.cnblogs.com/duyinqiang/p/5696253.html

1 選藍色字體方案,不要選紅色方案。具體解釋見下方文字:

爲了減少db的讀壓力,加快讀速度,系統使用cache做緩存,會引起cache一致性問題。因爲db會有事務性導致回滾,而cache無法回滾,會導致髒數據。

一般情況下,我們會在保存數據時,先穿透保存到DB中,再同步數據到redis中。

爲了保證存儲層對外層透明,我們會把DB與redis操作封裝,對上層調用來說完全透明,不關心數據具體如何存儲。

例如在我們的實際業務中有如下場景:A表插入一條數據,同步到redis中,B表插入一條數據,同步到redis中。如果B表插入數據失敗,事務回滾,A表中數據可以回滾,但是redis無法回滾。會導致redis中有髒數據。

facebook的一篇論文給出如下設計:

查詢:先查詢cache,miss時查詢db,寫入cache

寫:寫db成功後,失效cache

重點說下寫:如果寫db成功後,寫cache,會有事務性和併發性兩方面問題。

1.事務性問題:一個事務包含多個db操作,操作一些db成功,寫cache成功,操作二寫db失敗,事務回滾,db數據回滾,cache無法回滾,導致髒數據。

2.併發性問題:兩個更新操作併發,如更新名字,並且cache中key以名字爲關鍵字,更新一寫db成功,寫緩存XXXX_name1成功。更新二寫db成功,寫緩存XXXX_name2成功。導致cache髒數據。

二 :選藍色方案可能出現以下問題

一、需求緣起

上一篇《緩存架構設計細節二三事》(點擊查看)引起了廣泛的討論,其中有一個結論:當數據發生變化時,“先淘汰緩存,再修改數據庫”這個點是大家討論的最多的。

 

上篇文章得出這個結論的依據是,由於操作緩存與操作數據庫不是原子的,非常有可能出現執行失敗。


假設先寫數據庫,再淘汰緩存:第一步寫數據庫操作成功,第二步淘汰緩存失敗,則會出現DB中是新數據,Cache中是舊數據,數據不一致【如上圖:db中是新數據,cache中是舊數據】。

 


假設先淘汰緩存,再寫數據庫:第一步淘汰緩存成功,第二步寫數據庫失敗,則只會引發一次Cache miss【如上圖:cache中無數據,db中是舊數據】。

 

結論:先淘汰緩存,再寫數據庫。

 

引發大家熱烈討論的點是“先操作緩存,在寫數據庫成功之前,如果有讀請求發生,可能導致舊數據入緩存,引發數據不一致”,這就是本文要討論的主題。

 

二、爲什麼數據會不一致

回顧一下上一篇文章中對緩存、數據庫進行讀寫操作的流程。

寫流程:

(1)先淘汰cache

(2)再寫db

讀流程:

(1)先讀cache,如果數據命中hit則返回

(2)如果數據未命中miss則讀db

(3)將db中讀取出來的數據入緩存

 

什麼情況下可能出現緩存和數據庫中數據不一致呢?


在分佈式環境下,數據的讀寫都是併發的,上游有多個應用,通過一個服務的多個部署(爲了保證可用性,一定是部署多份的),對同一個數據進行讀寫,在數據庫層面併發的讀寫並不能保證完成順序,也就是說後發出的讀請求很可能先完成(讀出髒數據):

(a)發生了寫請求A,A的第一步淘汰了cache(如上圖中的1)

(b)A的第二步寫數據庫,發出修改請求(如上圖中的2)

(c)發生了讀請求B,B的第一步讀取cache,發現cache中是空的(如上圖中的步驟3)

(d)B的第二步讀取數據庫,發出讀取請求,此時A的第二步寫數據還沒完成,讀出了一個髒數據放入cache(如上圖中的步驟4)

即在數據庫層面,後發出的請求4比先發出的請求2先完成了,讀出了髒數據,髒數據又入了緩存,緩存與數據庫中的數據不一致出現了

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章