Mysql數(shù)據(jù)庫和Redis雙寫不一致方案討論 极颓,如何保證數(shù)據(jù)庫和緩存雙寫一致性?

mysql數(shù)據(jù)庫和redis雙寫不一致方案討論 群嗤,如何保證數(shù)據(jù)庫和緩存雙寫一致性菠隆?

緩存和數(shù)據(jù)庫之間所有的策略關系如下:
在高并發(fā)應用場景下,如果是對數(shù)據(jù)一致性要求高的情況下狂秘,要定位好導致數(shù)據(jù)和緩存不一致的原因骇径。
解決高并發(fā)場景下數(shù)據(jù)一致性的方案有兩種,分別是延時雙刪策略和異步更新緩存兩種方案者春。
另外破衔,設置緩存的過期時間是保證數(shù)據(jù)保持一致性的關鍵操作,需要結(jié)合業(yè)務進行合理的設置钱烟。

第一種:延時雙刪

一晰筛、先刪除緩存,再更新數(shù)據(jù)庫

1.如果先刪除Redis緩存數(shù)據(jù)拴袭,然而還沒有來得及寫入MySQL读第,另一個線程就來讀取。發(fā)現(xiàn)緩存為空拥刻,則去Mysql數(shù)據(jù)庫中
讀取舊數(shù)據(jù)寫入緩存怜瞒,次實緩存數(shù)據(jù)為臟數(shù)據(jù),然后更新數(shù)據(jù)庫后般哼,發(fā)現(xiàn)Redis和Mysql數(shù)據(jù)不一致
一吴汪、先更新數(shù)據(jù)庫惠窄,再刪除緩存
1.如果先更新數(shù)據(jù)庫,但是寫庫成功漾橙,此時線程掛掉了杆融,導致刪除緩存失敗,這個時候其他線程讀取數(shù)據(jù)庫就是舊數(shù)據(jù)庫
因為寫和讀是并發(fā)的近刘,沒法保證順序,就會出現(xiàn)緩存和數(shù)據(jù)庫的數(shù)據(jù)不一致的問題
解決方案:延時雙刪
[在寫庫前后都進行redis.del(key)操作,并且設定合理的超時時間

 public void write (String key, Object data ){
            redis.delKey(key);
            db.updateData(data);
            Thread.sleep(500);
            redis.delKey(key);
        }

具體步驟
1臀晃、先刪除緩存
2觉渴、再寫數(shù)據(jù)庫
3、休眠500毫秒
4徽惋、再次刪除緩存
問題:這個500毫秒怎么確定的案淋,具體該休眠多久時間呢?
1险绘、需要評估自己的項目的讀數(shù)據(jù)業(yè)務邏輯的耗時踢京。
2、這么做的目的宦棺,就是確保讀請求結(jié)束瓣距,寫請求可以刪除讀請求造成的緩存臟數(shù)據(jù)。
3代咸、當然這種策略還要考慮redis和數(shù)據(jù)庫主從同步的耗時蹈丸。
4、最后的的寫數(shù)據(jù)的休眠時間:則在讀數(shù)據(jù)業(yè)務邏輯的耗時基礎上呐芥,加幾百ms即可逻杖。
比如:休眠1秒。

設置緩存過期時間是關鍵點
1思瘟、從理論上來說荸百,給緩存設置過期時間,是保證最終一致性的解決方案
2滨攻、所有的寫操作以數(shù)據(jù)庫為準够话,只要到達緩存過期時間,緩存刪除
3光绕、如果后面還有讀請求的話更鲁,就會從數(shù)據(jù)庫中讀取新值然后回填緩存

方案缺點
結(jié)合雙刪策略+緩存超時設置,這樣最差的情況就是:
1奇钞、在緩存過期時間內(nèi)發(fā)生數(shù)據(jù)存在不一致
2澡为、同時又增加了寫請求的耗時。

第二種:異步更新緩存(基于Mysql binlog的同步機制)

整體思路

1景埃、涉及到更新的數(shù)據(jù)操作媒至,利用Mysql binlog 進行增量訂閱消費
2顶别、將消息發(fā)送到消息隊列
3、通過消息隊列消費將增量數(shù)據(jù)更新到Redis上
4拒啰、.操作情況

讀取Redis緩存:熱數(shù)據(jù)都在Redis上
寫Mysql:增刪改都是在Mysql進行操作
更新Redis數(shù)據(jù):Mysql的數(shù)據(jù)操作都記錄到binlog驯绎,通過消息隊列及時更新到Redis上
Redis更新過程
數(shù)據(jù)操作主要分為兩種:
1、一種是全量(將所有數(shù)據(jù)一次性寫入Redis)
2谋旦、一種是增量(實時更新)

這里說的是增量,指的是mysql的update剩失、insert、delate變更數(shù)據(jù)册着。
讀取binlog后分析 拴孤,利用消息隊列,推送更新各臺的redis緩存數(shù)據(jù)。

1甲捏、這樣一旦MySQL中產(chǎn)生了新的寫入演熟、更新、刪除等操作司顿,就可以把binlog相關的消息推送至Redis
2芒粹、Redis再根據(jù)binlog中的記錄,對Redis進行更新
3大溜、其實這種機制化漆,很類似MySQL的主從備份機制,因為MySQL的主備也是通過binlog來實現(xiàn)的數(shù)據(jù)一致性
這里的消息推送工具你也可以采用別的第三方:kafka钦奋、rabbitMQ等來實現(xiàn)推送更新Redis!

以下是具體問題分析:

1.先更新數(shù)據(jù)庫获三,再更新緩存(一般不使用)
解釋:如果緩存數(shù)據(jù)不是直接從數(shù)據(jù)庫中查詢出來的,而是需要經(jīng)過一系列的運算锨苏,這樣更新緩存的代價很高疙教,如果此時有很多請求對數(shù)據(jù)庫進行 寫數(shù)據(jù)的操作但是讀請求并不多,那么此時如果每次寫請求都更新一下緩存伞租,那么性能損耗是非常大的贞谓,如果讀多寫多則更不可取,可能出現(xiàn)數(shù)據(jù)不一致的情況

2.先更新數(shù)據(jù)庫葵诈,再刪除緩存問題(可以將刪除的任務放入MQ)
解釋:這一種情況也會出現(xiàn)問題裸弦,比如更新數(shù)據(jù)庫成功了,但是在刪除緩存的階段出錯了沒有刪除成功作喘,那么此時再讀取緩存的時候每次都是錯誤的數(shù)據(jù)了理疙。

3.先更新緩存,再更新數(shù)據(jù)庫(一般不使用)
解釋:這種情況與第一種類似泞坦,所有緩存更新的操作都是不可取的窖贤,同時面臨突然很多寫請求很多時,緩存更新性能消耗代價太高同時可能造成數(shù)據(jù)不一致

4.先刪除緩存,再更新數(shù)據(jù)庫(刪除緩存失敗問題赃梧,延時雙刪)

先刪除緩存滤蝠,再更新數(shù)據(jù)庫


此時來了兩個請求,請求 A(更新操作) 和請求 B(查詢操作)請求 A 會先刪除 Redis 中的數(shù)據(jù)授嘀,然后去數(shù)據(jù)庫進行更新操作此時請求 B 看到 Redis 中的數(shù)據(jù)時空的物咳,會去數(shù)據(jù)庫中查詢該值,補錄到 Redis 中但是此時請求 A 并沒有更新成功蹄皱,或者事務還未提交

先刪除緩存览闰,再更新數(shù)據(jù)庫問題解決方案:延時雙刪


數(shù)據(jù)不一致最關鍵的點:就是更新操作的執(zhí)行流程提交事務過程中,是否有查詢請求巷折,搶先執(zhí)行完畢的情況压鉴,過程中也可以強制加鎖,保證更新操作完成盔几,才能進行數(shù)據(jù)查詢

先刪除緩存晴弃,再更新數(shù)據(jù)庫解決方案:延時雙刪掩幢,Mysql讀寫分離架構延時問題

問題延伸:但是上述的保證事務提交完以后再進行刪除緩存還有一個問題逊拍,就是如果你使用的是 Mysql 的讀寫分離的架構的話,那么主從延時問題


此時來了兩個請求际邻,請求 A(更新操作) 和請求 B(查詢操作)請求 A 更新操作芯丧,刪除了 Redis請求主庫進行更新操作,主庫與從庫進行同步數(shù)據(jù)的操作請 B 查詢操作世曾,發(fā)現(xiàn) Redis 中沒有數(shù)據(jù)去從庫中拿去數(shù)據(jù)此時同步數(shù)據(jù)還未完成缨恒,拿到的數(shù)據(jù)是舊數(shù)據(jù)

先刪除緩存,再更新數(shù)據(jù)庫解決方案:延時雙刪+讀寫分離架構(強制讀主庫)解決

先更新數(shù)據(jù)庫轮听,再刪除緩存解決數(shù)據(jù)一致性方案骗露,利用消息隊列進行刪除的補償


此時解決方案就是利用消息隊列進行刪除的補償。具體的業(yè)務邏輯用語言描述如下:請求 A 先對數(shù)據(jù)庫進行更新操作在對 Redis 進行刪除操作的時候發(fā)現(xiàn)報錯血巍,刪除失敗此時將Redis 的 key 作為消息體發(fā)送到消息隊列中系統(tǒng)接收到消息隊列發(fā)送的消息后再次對 Redis 進行刪除操作但是這個方案會有一個缺點就是會對業(yè)務代碼造成大量的侵入,深深的耦合在一起,所以這時會有一個優(yōu)化的方案寄猩,我們知道對 Mysql 數(shù)據(jù)庫更新操作后再 binlog 日志中我們都能夠找到相應的操作顶滩,那么我們可以訂閱 Mysql 數(shù)據(jù)庫的 binlog 日志對緩存進行操作。

先更新數(shù)據(jù)庫鲫凶,再刪除緩存禀崖,訂閱 binlog 日志解決代碼大量侵入問題

總結(jié):不同方案都有優(yōu)點和劣勢,需要結(jié)合自身的業(yè)務螟炫,選擇不同的方案波附,比如在第二種先刪除緩存,后更新數(shù)據(jù)庫這個方案最后討論了要更新 Redis 的時候強制走主庫查詢就能解決問題,那么這樣的操作會對業(yè)務代碼進行大量的侵入叶雹,但是不需要增加整體的服務的復雜度财饥。最后一種方案我們最后討論了利用訂閱 binlog 日志進行搭建獨立系統(tǒng)操作 Redis,這樣的就增加了系統(tǒng)復雜度折晦。這個時候要求我們站在系統(tǒng)全局角度去考量钥星,選用那種方案更適合
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市满着,隨后出現(xiàn)的幾起案子谦炒,更是在濱河造成了極大的恐慌,老刑警劉巖风喇,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宁改,死亡現(xiàn)場離奇詭異,居然都是意外死亡魂莫,警方通過查閱死者的電腦和手機还蹲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耙考,“玉大人谜喊,你說我怎么就攤上這事【胧迹” “怎么了斗遏?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鞋邑。 經(jīng)常有香客問我诵次,道長,這世上最難降的妖魔是什么枚碗? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任逾一,我火速辦了婚禮,結(jié)果婚禮上肮雨,老公的妹妹穿的比我還像新娘遵堵。我一直安慰自己,他們只是感情好酷含,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布鄙早。 她就那樣靜靜地躺著,像睡著了一般椅亚。 火紅的嫁衣襯著肌膚如雪限番。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天呀舔,我揣著相機與錄音弥虐,去河邊找鬼扩灯。 笑死,一個胖子當著我的面吹牛霜瘪,可吹牛的內(nèi)容都是我干的珠插。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颖对,長吁一口氣:“原來是場噩夢啊……” “哼捻撑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缤底,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤顾患,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后个唧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體江解,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年徙歼,在試婚紗的時候發(fā)現(xiàn)自己被綠了犁河。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡魄梯,死狀恐怖桨螺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情画恰,我是刑警寧澤彭谁,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布吸奴,位于F島的核電站允扇,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏则奥。R本人自食惡果不足惜考润,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望读处。 院中可真熱鬧糊治,春花似錦、人聲如沸罚舱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管闷。三九已至粥脚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間包个,已是汗流浹背刷允。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人树灶。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓纤怒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親天通。 傳聞我的和親對象是個殘疾皇子泊窘,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容