前言
在分布式系統中,緩存和數據庫同時存在時,如果有寫操作,先操作數據庫還是先操作緩存呢?本文將分5種方案展開闡述對比,謝謝閱讀~github地址,衷心感謝每一顆star
?https://github.com/whx123/JavaHome?
緩存維護方案一
如果是一讀(線程B)一寫(線程A)操作,「先操作緩存,再操作數據庫」。流程圖如下所示:
1.線程A發起一個寫操作,第一步del cache
2.線程A第二步寫入新數據到DB
3.線程B發起一個讀操作,cache miss緩存失效了。
4.線程B從DB獲取最新數據
5.線程B執行set cache,把從DB讀到的數據,更新到緩存。
「這樣看,沒啥問題」。
1.線程A發起一個寫操作,第一步del cache
2.此時線程B發起一個讀操作,cache miss
3.線程B繼續讀DB,讀出來一個老數據
4.然后老數據設置入cache
5.線程A寫入DB最新的數據
OK,醬紫,就有問題了吧,老數據入到緩存了,「每次讀都是老數據啦,緩存與數據與數據庫數據不一致了」。
緩存維護方案二
上個方案是一讀一寫,如果是雙寫操作,「先操作緩存,在操作數據庫」,會怎么樣呢?
1.線程A發起一個寫操作,第一步set cache
2.線程A第二步寫入新數據到DB
3.線程B發起一個寫操作,set cache
4.線程B第二步寫入新數據到DB
「這樣看,也沒啥問題。」
1.線程A發起一個寫操作,第一步set cache
2.線程B發起一個寫操作,第一步set cache
3.線程B寫入數據庫到DB
4.線程A寫入數據庫到DB
執行完后,緩存保存的是B操作后的數據,數據庫是A操作后的數據,「緩存和數據庫數據不一致了」。
緩存維護方案三
一寫(線程A)一讀(線程B)操作,「先操作數據庫,再操作緩存」。
1.線程A發起一個寫操作,第一步write DB
2.線程A第二步del cache
3.線程B發起一個讀操作,cache miss
4.線程B從DB獲取最新數據
5.線程B同時set cache
有些朋友可能認為,在第2步刪除緩存之前,線程B讀過來呢?這時候,讀到的是緩存老數據,這個可以認為是正常業務邏輯呀,下次再讀取就是正確數據了。這種方案「沒有明顯的并發問題」,但是呢,「步驟二刪除緩存失敗」,還是個問題。不過概率比較小,「優于方案一和方案二」,平時工作中也是使用方案三。綜上對比,我們一般采用方案三,但是有沒有完美全解決方案三的弊端的方法呢?
緩存維護方案四
這個是方案三的改進方案,都是先操作數據庫再操作緩存
通過數據庫的「binlog」來「異步淘汰key」,以mysql為例 可以「使用阿里的canal將binlog日志采集發送到MQ隊列」里面,然后「通過ACK機制 確認處理」這條更新消息,刪除緩存,保證數據緩存一致性。但是呢還有個問題,「如果是主從數據庫呢」?
緩存維護方案五
主從DB問題:因為主從DB同步存在延時時間。如果刪除緩存之后,數據同步到備庫之前已經有請求過來時,「會從備庫中讀到臟數據」,如何解決呢?
緩存維護總結
綜上所述,在分布式系統中,緩存和數據庫同時存在時,如果有寫操作的時候,「先操作數據庫,再操作緩存」。如下:
1.讀取緩存中是否有相關數據
2.如果緩存中有相關數據value,則返回
3.如果緩存中沒有相關數據,則從數據庫讀取相關數據放入緩存中key-》value,再返回
4.如果有更新寫數據,則先操作數據庫,再操作緩存
5.為了保證第四步更新緩存成功,使用binlog異步通知操作
6.如果是主從數據庫,binglog取自于從庫
7.如果是一主多從,每個從庫都要采集binlog,然后消費端收到最后一臺binlog數據才刪除緩存
責任編輯:haq
-
緩存
+關注
關注
1文章
240瀏覽量
26701 -
數據庫
+關注
關注
7文章
3827瀏覽量
64514 -
分布式系統
+關注
關注
0文章
146瀏覽量
19276
原文標題:并發環境下,先操作數據庫還是先操作緩存?
文章出處:【微信號:DBDevs,微信公眾號:數據分析與開發】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論