1. 程式人生 > >redis與Mysql的資料一致性

redis與Mysql的資料一致性

為了減少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髒資料。

這裡再說一下一般更新操作順序是失效cache,寫db,寫cache。會有併發問題。

兩個併發操作,更新和讀,左邊寫執行緒,右邊為讀執行緒

①更新操作刪除cache

②讀操作讀cache,miss

③讀db,此時是舊資料

④寫db,寫cache

⑤寫cache 導致cache中髒資料。

雖然寫db成功後,失效cache也會有併發問題:更新和讀併發

①查詢cache

②寫db,失效cache

③寫chache

導致cache中髒資料,但是概率極低,並且一般db中寫時間長於讀時間,並且寫會鎖表,讀需要在寫前進入,並且要晚於寫操作更新快取,所以發生概率極低。

解決方法是 2PC或是Paxos協議,代價較大。

所以我們採用的方式是:

寫資料只寫db

更新資料先更新db,再失效cache

讀資料,先讀cache,未命中讀db,寫入cache