新聞中心
如何解決Redis緩存和MySQL數(shù)據(jù)一致性的問題?
Redis緩存和MySQL數(shù)據(jù)一致性的問題,相信大家在大量使用redis緩存進(jìn)行業(yè)務(wù)開發(fā)的場景下是一定要考慮的問題。

總有運(yùn)營、產(chǎn)品、測試人員過來問你為什么我剛剛更新了一條數(shù)據(jù),APP上還是原來的數(shù)據(jù)呢?你總是一句話:“加了緩存,等會(huì)兒就好”。有可能是1分鐘,有可能是半小時(shí)。問你的都屬于關(guān)系不錯(cuò),不問你直接給你提bug你也沒辦法。
下面就分享一下我個(gè)人在工作中對如何解決redis緩存和MySQL數(shù)據(jù)一致性的一些心得:
大家看了這個(gè)圖是不是就知道什么意思了?一個(gè)請求過來查詢數(shù)據(jù),我先看看redis有沒有,有直接返回,沒有就去數(shù)據(jù)庫查出來,順便同步到redis,設(shè)置一下過期時(shí)間。下次同樣的數(shù)據(jù)查詢r(jià)edis緩存就可以直接返回了。是不是很簡單很粗暴?在實(shí)時(shí)性要求不高的場景下,這種方式我估計(jì)是大家最常用的一種方式。但是他有幾個(gè)問題:
無法保證一致性:數(shù)據(jù)庫更改了數(shù)據(jù),redis里的數(shù)據(jù)就和數(shù)據(jù)庫不一致了,產(chǎn)生臟讀;
緩存雪崩:這種方案要求redis里的緩存必須設(shè)置有效期,如果在同一時(shí)間大面積過期,所有請求壓力都指向數(shù)據(jù)庫,這個(gè)時(shí)候數(shù)據(jù)庫頂不住壓力就會(huì)宕機(jī),然后整個(gè)世界都安靜了;
緩存穿透:查詢一個(gè)數(shù)據(jù),緩存沒有,去查詢數(shù)據(jù)庫,數(shù)據(jù)庫也沒有,怎么辦?這樣的請求多了對數(shù)據(jù)庫也是壓力,沒有數(shù)據(jù)的時(shí)候也需要在redis緩存一個(gè)空值。
針對第一種方案的問題,那么大多數(shù)時(shí)候我們會(huì)繼續(xù)做一個(gè)job,去定時(shí)同步數(shù)據(jù)庫里的數(shù)據(jù)都redis緩存中,我們的業(yè)務(wù)請求直接查詢r(jià)edis緩存,無論有或者沒有數(shù)據(jù)都直接返回結(jié)果。這樣可以避免緩存穿透、緩存雪崩等問題,也能緩解redis緩存和數(shù)據(jù)庫不一致的情況,但是還無法徹底解決一致性的問題。在job的間隔期內(nèi)對數(shù)據(jù)的修改必須要等到下一次job的運(yùn)行。
對軟件開發(fā)同學(xué)來說,這個(gè)場景太常見了。基本的思路是:mysql數(shù)據(jù)發(fā)生變更的時(shí)候,要及時(shí)清除redis緩存。那究竟要怎樣清除呢?
分兩種情況來說吧。
單集群。在redis集群和mysql集群都是單集群部署的情況下,需要確保如果redis查不到數(shù)據(jù)讀取mysql主庫來填充數(shù)據(jù),此時(shí)只需要在mysql變更生效后,直接調(diào)用redis清緩存即可。
多集群。在redis集群和mysql集群都是多地多機(jī)房的部署情況下。采用單集群清緩存策略清除本機(jī)房redis集群緩存后,延遲消息通知其他機(jī)房redis集群(確保其他機(jī)房mysql集群已收到本機(jī)房mysql集群的binlog變更消息并將變更生效)。
希望能解答您的問題,喜歡的話可以關(guān)注下我哈
要看應(yīng)用場景,數(shù)據(jù)變動(dòng)頻繁的環(huán)境中,使用讀緩存是毫無意義的,反而加重系統(tǒng)負(fù)荷,因?yàn)橐ㄙM(fèi)額外資源維護(hù)緩存和數(shù)據(jù)源的一致性。
其實(shí)redis可以當(dāng)作數(shù)據(jù)庫的元數(shù)據(jù)使用,設(shè)計(jì)好數(shù)據(jù)結(jié)構(gòu)就是一個(gè)簡單的關(guān)系型庫,業(yè)務(wù)數(shù)據(jù)完全放到redis中運(yùn)行,MySQL當(dāng)作后備庫使用。redis也有持久化機(jī)制而且很容易做鏡像,因此可以在很大時(shí)間粒度上進(jìn)行數(shù)據(jù)同步,比如一天同步一次。而業(yè)務(wù)層只操作redis,與數(shù)據(jù)庫完全剝離,即使數(shù)據(jù)庫掛掉也不會(huì)導(dǎo)致業(yè)務(wù)中斷。
隨著技術(shù)發(fā)展,現(xiàn)在項(xiàng)目技術(shù)選型不像從前那樣單一的,特別是在高并發(fā)場景下的項(xiàng)目,都是多種技術(shù)配套著來使用。在以前,對于用戶數(shù)據(jù)無論是增刪改查,我們都是直接操作數(shù)據(jù)庫的,但在高并發(fā)場景下這樣做顯然是不合理的,于是乎我們在DB層之前加上Cache層,以此來緩解DB層的壓力。
在業(yè)界通常是將MySQL作為數(shù)據(jù)最終落地的存儲(chǔ)方案,而用Redis來緩存熱點(diǎn)數(shù)據(jù)。一般是讀數(shù)據(jù)是從Redis中讀取,增刪改則是操作MySQL。但是這樣會(huì)存在一個(gè)問題,即:讀操作和寫操作是并發(fā)的,執(zhí)行順序無法保證,這樣很容易出現(xiàn)緩存數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)不一致。
舉例說明一下:
假設(shè)我們更新了數(shù)據(jù)庫后,緩存一直沒有失效,那我們從緩存中讀取的就是臟數(shù)據(jù)。
假設(shè)緩存中的數(shù)據(jù)不存在,我們從數(shù)據(jù)庫中讀取數(shù)據(jù)然后存入緩存,此時(shí)數(shù)據(jù)庫剛好更新,那在緩存期間內(nèi),這個(gè)緩存數(shù)據(jù)就是臟數(shù)據(jù)。
如何避免Redis和MySQL中數(shù)據(jù)一致性問題呢?結(jié)合我的經(jīng)驗(yàn)給出一些方案供大家參考:
1、首先確定你的業(yè)務(wù)是否要求緩存和數(shù)據(jù)庫之間是強(qiáng)一致性關(guān)系
如果你的業(yè)務(wù)要求數(shù)據(jù)庫和緩存之間是強(qiáng)一致性,那你要做的就是確保每次更新了MySQL后就同步更新Redis;
如果不需要強(qiáng)一致性,那我們合理控制好緩存的TTL即可。
2、借助MQ消息來更新緩存
到此,以上就是小編對于redis事務(wù)能保證一致性嗎為什么的問題就介紹到這了,希望這1點(diǎn)解答對大家有用。
當(dāng)前文章:redis事務(wù)能保證一致性嗎
轉(zhuǎn)載注明:http://www.dlmjj.cn/article/cdsiieh.html


咨詢
建站咨詢
