【大廠面試01期】高併發場景下,如何保證緩存與數據庫一致性?_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

PS:本文已收錄到1.1K Star數開源學習指南——《大廠面試指北》,如果想要了解更多大廠面試相關的內容及獲取《大廠面試指北》離線PDF版,請掃描下方二維碼碼關注公眾號“大廠面試”,謝謝大家了!項目地址:https://github.com/NotFound9/interviewGuide

《大廠面試指北》項目截圖:

獲取《大廠面試指北》離線PDF版,請掃描下方二維碼關注公眾號“大廠面試”

面試題:高併發場景下,如何保證緩存與數據庫一致性?

問題分析

我們日常開發中,對於緩存用的最多的場景就像下圖一樣,可能僅僅是對數據進行緩存,減輕數據庫壓力,縮短接口響應時間。

這種方案在不需要考慮高併發得去寫緩存,高併發得讀寫緩存時,是不會有問題,但是如果是在高併發場景下,要保證緩存和數據庫的一致性,至少需要解決以下問題:

高併發寫時的數據不一致問題

高併發讀寫時,請求執行各步驟的順序是不可控的。假設此時有一個請求A,B都在在執行寫流程,請求A是需要將某個數據改成1,請求B是需要將某個數據改為2,執行操作如下時就會導致數據不一致的問題:

1.請求A執行操作1.1刪除緩存。

2.請求A執行操作1.2更新數據庫,將值改為1。

3.請求B執行操作1.1刪除緩存。

4.請求B執行操作1.2更新數據庫,將值改為2

5.假設說請求B所在服務器網絡延遲比較低,請求B先更新緩存,此時緩存中的key對應的value是2。

6.請求A更新緩存,將緩存中B更新的數據進行覆蓋,將key對應的值改為1。

此時數據庫中是B修改后的數據,值為2,而緩存中的數據是1,這樣在緩存過期錢,用戶讀到的都是臟數據,與數據庫不一致。

高併發讀寫時的數據不一致的問題

高併發讀寫時,請求執行各步驟的順序是不可控的。假設此時有一個請求A在執行寫流程,將原值由1改成2,請求B執行讀流程,執行操作如下時就會導致數據不一致的問題:

1.寫請求A執行1.1操作刪除緩存key,value是原值1。

2.讀請求B執行2.1操作發現緩存中沒有數據,就去執行2.2操作讀數據庫,讀到舊數據,值為1。

3.寫請求A執行1.2操作更新數據庫,將數據由1改為2。

4.寫請求A執行1.3操作更新緩存,此時緩存中的數據key對應的value是2。

5.讀請求B執行2.3操作更新緩存,將之前讀到的舊數據1設置到緩存中,此時緩存中的數據key對應的value是1。

所以如果說讀請求B所在服務器網絡延遲比較高,去執行2.3操作比寫請求A晚,就會導致寫請求A更新完緩存后,讀請求B使用之前讀到的舊數據去更新緩存,此時緩存中數據就與數據庫中的不一致。

解決方案

保證數據一致性,網上有很多種方案,例如:

1.先刪除緩存,再更新數據庫。

2.先更新數據庫,再刪除緩存。

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

3.先刪除緩存,再更新數據庫,然後異步延遲一段時間再去刪一次緩存。

但是這些方案都是存在各種各樣的問題,這裏篇幅有限,只給出目前相對正確的三套方案,目前的這些方案也有自己的局限性。

方案1.寫請求串行化

寫請求

1.寫請求更新之前先獲取分佈式鎖,獲得之後才能去數據庫更新這個數據,獲取不到就進行等待,超時后就返回更新失敗。

2.更新完之後去刷新緩存,如果刷新失敗,放到內存隊列中進行重試(重試時取數據庫最新數據更新緩存)。

讀請求

讀請求發現緩存中沒有數據時,直接去讀取數據庫,讀完更新緩存。

總結

這種技術方案通過對寫請求的實現串行化來保證數據一致性,但是會導致吞吐量變低。比較適合銀行相關的業務,因為對於銀行項目來說,保證數據一致性比可用性更加重要,就像是去存款機存錢,取錢時,為了保證賬戶安全,都是會讓用戶執行操作后,等待一段時間才能獲得反饋,這段時間其實取款機是不可用的。

方案2.先更新數據庫,異步刪除緩存,刪除失敗后重試

1.先更新數據庫

2.異步刪除緩存(如果數據庫是讀寫分離的,那麼刪除緩存時需要延遲刪除,否則可能會在刪除緩存時,從庫還沒有收到更新后的數據,其他讀請求就去從庫讀到舊數據然後設置到緩存中。)

3.刪除緩存失敗時,將刪除的key放到內存隊列或者是消息隊列中進行異步重試

發散思考

在更新完數據庫后,我們為什麼不直接更新,而是採用刪除緩存呢?

這是因為直接更新緩存的話,在高併發場景下,有多個更新請求時,難以保證后更新數據庫的請求會後更新緩存,也就是上面的高併發寫問題。如果採用刪除緩存,可以讓下次讀時讀取數據庫,更新緩存,保證一致性。

方案3.業務項目更新數據庫,其他項目訂閱binlog更新

1.業務項目直接更新數據庫。

2.cannal項目會讀取數據庫的binlog,然後解析后發消息到kafka。

3.然後緩存更新項目訂閱topic,從kafka接收到更新數據庫操作的消息后,更新緩存,更新緩存失敗時,新建異步線程去重試或者將操作發到消息隊列,後續再進行處理。

總結:

但是這種方案在更新數據庫后,緩存中還是舊值,必須等緩存更新項目消費消息后,更新緩存,緩存中才是最新值。所以更新操作完成與更新生效之間會有一定的延遲。

最後

大家有了解其他的技術方案,歡迎進群一起討論!

評論裏面有朋友問延時雙刪策略是什麼?

這裏解釋一下:延時雙刪策略就是先刪除緩存,再更新數據庫,再異步過一小段時間后刪除緩存(時間取決於MySQL主從同步的時間)。

是因為MySQL如果是讀寫分離時(寫請求寫主庫,讀請求讀從庫),我們更新主庫后,需要一段時間,從庫才會收到更新。

如果是寫請求更新主庫后,第二次立即刪除緩存,MySQL從庫還沒有收到更新,還是舊數據,那麼讀請求直接從庫讀到舊數據,設置到緩存的數據就是舊數據,就會數據不一致,所以這也是延時雙刪策略提出的初衷。

參考鏈接:

https://www.cnblogs.com/-wenli/p/11474164.html

https://www.cnblogs.com/rjzheng/p/9041659.html

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。