並發環境下,先操作資料庫還是先操作緩存?

2020-12-15 騰訊網

作者 | 撿田螺的小男孩

頭圖 | CSDN 下載自東方IC

前言

在分布式系統中,緩存和資料庫同時存在時,如果有寫操作的時候,先操作資料庫還是先操作緩存呢?先思考一下,可能會存在哪些問題,再往下看。下面我分幾種方案闡述。

github地址:https://github.com/whx123/JavaHome

緩存維護方案一

假設有一寫(線程A)一讀(線程B)操作,先操作緩存,在操作資料庫。如下流程圖所示:

1)線程A發起一個寫操作,第一步del cache

2)線程A第二步寫入新數據到DB

3)線程B發起一個讀操作,cache miss,

4)線程B從DB獲取最新數據

5)請求B同時set cache

這樣看,沒啥問題。我們再看第二個流程圖,如下:

1)線程A發起一個寫操作,第一步del cache

2)此時線程B發起一個讀操作,cache miss

3)線程B繼續讀DB,讀出來一個老數據

4)然後老數據入cache

5)線程A寫入了最新的數據

OK,醬紫,就有問題了吧,老數據入到緩存了,每次讀都是老數據啦,緩存與數據與資料庫數據不一致

緩存維護方案二

雙寫操作,先操作緩存,在操作資料庫

1)線程A發起一個寫操作,第一步set cache

2)線程A第二步寫入新數據到DB

3)線程B發起一個寫操作,set cache,

4)線程B第二步寫入新數據到DB

這樣看,也沒啥問題。,但是有時候可能事與願違,我們再看第二個流程圖,如下:

1)線程A發起一個寫操作,第一步set cache

2)線程B發起一個寫操作,第一步setcache

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

這種方案沒有明顯的並發問題,但是有可能步驟二刪除緩存失敗,雖然概率比較小,優於方案一和方案二,平時工作中也是使用方案三。

綜上對比,我們一般採用方案三,但是有沒有完美全解決方案三的弊端的方法呢?

緩存維護方案四

這個是方案三的改進方案,都是先操作資料庫再操作緩存,我們來看一下流程圖:

通過資料庫的binlog異步淘汰key,以mysql為例可以使用阿里的canal將binlog日誌採集發送到MQ隊列裡面,然後通過ACK機制確認處理這條更新消息,刪除緩存,保證數據緩存一致性。

但是呢還有個問題,如果是主從資料庫呢

緩存維護方案五

主從DB問題:因為主從DB同步存在同時延時時間如果刪除緩存之後,數據同步到備庫之前已經有請求過來時,會從備庫中讀到髒數據,如何解決呢?解決方案如下流程圖:

緩存維護總結

綜上所述,在分布式系統中,緩存和資料庫同時存在時,如果有寫操作的時候,先操作資料庫,再操作緩存。如下:

(1)讀取緩存中是否有相關數據

(2)如果緩存中有相關數據value,則返回

(3)如果緩存中沒有相關數據,則從資料庫讀取相關數據放入緩存中key->value,再返回

(4)如果有更新數據,則先更新數據,再刪除緩存

(5)為了保證第四步刪除緩存成功,使用binlog異步刪除

(6)如果是主從資料庫,binglog取自於從庫

(7)如果是一主多從,每個從庫都要採集binlog,然後消費端收到最後一臺binlog數據才刪除緩存

相關焦點

  • Redis緩存與資料庫數據一致性
    這裡有一點需要提一下:更新「某張表多行記錄「時,這個操作要在一個事務內,不然並發問題依然存在,正如前面分析的依然是並發問題即使對於缺點1我們提出了改進方案,雖然它解決了部分問題,但在極端場景下依然存在並發問題。
  • 緩存與資料庫的數據一致性的解決方案
    雖說這樣能減輕資料庫壓力,但是如果修改刪除數據,在多線程高並發的場景下會有可能導致緩存和資料庫數據不一致問題,那該如何解決呢?分析問題與解決方案場景一:問題的根源其實是讀數據與寫數據請求同時並發時,資料庫與緩存數據已更新,但訪問的數據還是老數據,出現了髒讀數據,我們假設讀請求流程沒有問題,那就分析寫請求流程的優化1.
  • 分布式之資料庫和緩存雙寫一致性方案解析
    首先,緩存由於其高並發和高性能的特性,已經在項目中被廣泛使用。在讀取緩存方面,大家沒啥疑問,都是按照下圖的流程來進行業務操作。  文章結構  本文由以下三個部分組成1、講解緩存更新策略2、對每種策略進行缺點分析3、針對缺點給出改進方案  正文  先做一個說明,從理論上來說,給緩存設置過期時間,是保證最終一致性的解決方案。這種方案下,我們可以對存入緩存的數據設置過期時間,所有的寫操作以資料庫為準,對緩存操作只是盡最大努力即可。
  • ASP.net 緩存技術:延遲操作高級用法
    本文提到的【延遲操作】方法(如:延遲合併寫入資料庫)屬於我的經驗總結,希望大家能喜歡這個思路。  Cache的基本用途  提到Cache,不得不說說它的主要功能:改善程序性能。然而,它們有一點小的區別:當要加入的緩存項已經在Cache中存在時,Insert將會覆蓋原有的緩存項目,而Add則不會修改原有緩存項。  也就是說:如果您希望某個緩存項目一旦放入緩存後,就不要再被修改,那麼調用Add確實可以防止後來的修改操作。 而調用Insert方法,則永遠會覆蓋已存在項(哪怕以前是調用Add加入的)。
  • 大話程序猿眼裡的高並發
    最後我還是建議所有的數據操作都寫在一個sql事務裡面,  這樣在添加失敗,或者編輯用戶積分失敗的時候可以回滾數據。如例子3(通過程序代碼防止包並發下的數據錯亂問題)需求點:【緩存數據到cache裡】,當緩存不存在的時候,從資料庫中獲取並保存在cache裡,如果存在從cache裡獲取,每天10點必須更新一次,其他時間點緩存兩個小時更新一次到10點的時候,凡是打開頁面的用戶會自動刷新頁面
  • 大話程序猿眼裡的高並發 - OSCHINA - 中文開源技術交流社區
    最後我還是建議所有的數據操作都寫在一個sql事務裡面,  這樣在添加失敗,或者編輯用戶積分失敗的時候可以回滾數據。如例子3(通過程序代碼防止包並發下的數據錯亂問題)需求點:【緩存數據到cache裡】,當緩存不存在的時候,從資料庫中獲取並保存在cache裡,如果存在從cache裡獲取,每天10點必須更新一次,其他時間點緩存兩個小時更新一次到10點的時候,凡是打開頁面的用戶會自動刷新頁面問題點:這裡有個邏輯用戶觸發緩存的更新,用戶刷新頁面,當緩存存在的時候,
  • 想用資料庫「讀寫分離」 請先明白「讀寫分離」解決什麼問題
    其實就是將資料庫分為了主從庫,一個主庫用於寫數據,多個從庫完成讀數據的操作,主從庫之間通過某種機制進行數據的同步,是一種常見的資料庫架構。一個組從同步集群,通常被稱為是一個「分組」。資料庫分組架構解決什麼問題?
  • 聊一聊緩存雙一致問題以及spring cache
    很多人的用法是用Spring cache整合Redis然後在service層方法上用註解的方式做緩存,可以說非常的方便。然而,你確定真的用對緩存了嗎?在高並發下又怎樣保證緩存中的數據和資料庫中的數據一致呢?現在我們就來嘮一嘮。
  • Redis 緩存雪崩、擊穿、穿透
    我刻意看了下我做過的項目感覺再吊的都不允許這麼大的QPS直接打DB去,不過沒慢SQL加上分庫,大表分表可能還還算能頂,但是跟用了Redis的差距還是很大或者設置熱點數據永遠不過期,有更新操作就更新緩存就好了(比如運維更新了首頁商品,那你刷下緩存就完事了,不要設置過期時間),電商首頁的數據也可以用這個操作,保險。那你了解緩存穿透和擊穿麼,可以說說他們跟雪崩的區別麼?
  • 實例解讀什麼是Redis緩存穿透、緩存雪崩和緩存擊穿
    如果對數據的一致性要求很高,那麼就不能使用緩存。另外的一些典型問題就是,緩存穿透、緩存雪崩和緩存擊穿。目前,業界也都有比較流行的解決方案。本篇文章,並不是要更加完美的解決這三個問題,也不是要顛覆業界流行的解決方案。而是,從實際代碼操作,來演示這三個問題現象。
  • Java面試題解析(事務+緩存+資料庫+多線程+JVM)
    1、原子性:事務是資料庫的邏輯工作單位,事務中包含的各操作要麼都做,要麼都不做。2、一致性:事務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態。因此當資料庫只包含成功事務提交的結果時,就說資料庫處於一致性狀態。
  • 一文搞定「關係型資料庫」與「非關係型資料庫」
    從技術的角度來看,彼時還處在Web應用發展的初期,網際網路技術架構還是最原始的單體架構,網民數量很少,一個伺服器完全足夠扛起用戶訪問的壓力。那個時期的關係型資料庫得到了較為廣泛的關注和應用,網站訪問量談不上什麼高並發、更別說什麼用戶體驗了,能玩得起就已經是完勝上億中國人了。
  • JAVA常見資料庫操作API
    cfg = new Configuration().configure();SessionFactory :Configuration對象根據當前的配置信息生成SessionFactory對象,SessionFactory對象中保存了當前資料庫的配置信息和所有映射關係以及預定義的SQL語句,同時還負責維護Hibernate的二級緩存
  • 先了解使用者操作,還是先畫 Wireframe?
    1.先出 Wireframe,再來想使用者會怎麼操作。2.先確認使用者會怎麼使用產品功能,再來思考 Wireframe 怎麼畫。課堂上我很強烈要求學員,做任何思考都要有「依據」,沒有依據憑空想像出來的設計很容易被推翻,也無法說服別人、讓別人理解自己的思考邏輯和原因。所以我的答案會是 2,先確認使用者會怎麼使用產品功能,再來思考 Wireframe 怎麼畫。
  • 循序漸進學MySQL,資料庫的基本操作,實戰出真知
    MySQL安裝好以後,首先需要創建資料庫,這是使用MySQL各種功能的前提。本文將詳細介紹數據的基本操作,主要內容包括:創建資料庫、刪除資料庫、不同類型的數據存儲引擎和存儲引擎的選擇。它的CPU效率可能是任何其他基於磁碟的關係資料庫引擎所不能匹敵的。(3) InnoDB 存儲引擎完全與MySQL伺服器整合,InnoDB 存儲引擎為在主內存中緩存數據和索引而維持它自己的緩衝池。InnoDB 將它的表和索引存在-一個邏輯表空間中,表空間可以包含數個文件(或原始磁碟分區)。這與MyISAM表不同,比如在MyISAM表中每個表被存在分離的文件中。
  • python對mysql資料庫的操作(一)
    在自動化測試中,某些人認為是沒有必要操作資料庫的,理由是大多數的自動化測試都是UI的,非接口的自動化測試,其實,在一個項目的自動化測試中,這種定義很模糊,或者說很不明確,比如在自動化測試中,怎麼來驗證用戶登錄成功,用戶註冊成功?先來說登錄,用戶登錄成功後,驗證點首先是用戶的暱稱,再有麼?
  • 大話|大話程序猿眼裡最全的高並發,快收藏!
    app後會操作,這些用戶不會高聚集,同時這些表又是大的數據表,業務很多,所以需要減少DB的查詢,優先查詢緩存,如果緩存不存在,再命中DB。一級緩存一級緩存就是使用站點伺服器去緩存數據,只緩存部分請求量大的數據,並且數據量還需要控制,一級緩存需要設置秒為單位的過期時間,具體業務場景看業務場景而定,目的是有高並發的時候可以讓數據獲取命中到一級緩存,減少nosql的壓力。
  • 通過加鎖控制Oracle資料庫並發事務
    在Oracle資料庫中要處理並發的話,可以通過加鎖,和設置只讀事務,以及設置隔離級別來控制處理並發。今天主要介紹的是通過加鎖來控制並發事務。在並發控制中,Oracle 主要利用了事務的特性和鎖的機制。只有當A事務完成寫操作並將鎖打開後,才運行其他事務的寫操作。我們通過加鎖可以防止兩個寫事務同時對-一個數據進行修改,所以也就不會出現寫數據丟失的問題。在執行UPDATE、INSERT和DELETE語句時,Oracle 會自動加「行鎖」,即對寫語句涉及的那些記錄加鎖。
  • 我的實戰經驗分享:深入淺出Python資料庫操作
    在實操之前,我們稍微先提一下環境配置什麼的。這裡我們儘可能地減少安裝環境配置等等的影響,不同系統上具體操作的差別不會太大。網絡上有非常多的Notebook基本操作的指引(網絡資料傳送門:https://zhuanlan.zhihu.com/p/33105153 )這裡不再贅述啦。上圖是我新建了一個文件夾,在裡面新建了一個ipynb文件(統一稱為Notebook文件)。OK!實驗環境準備就緒,可以繼續下一步啦。
  • 資料庫並發問題詳述
    首頁 > 語言 > 關鍵詞 > 資料庫最新資訊 > 正文 資料庫並發問題詳述