<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Redis與MySQL雙寫一致性是指在使用快取和資料庫同時儲存資料的場景下( 主要是存在高並行的情況),如何保證兩者的資料一致性(內容相同或者儘可能接近)。
正常業務流程:
讀沒什麼問題,關鍵就在於寫(更新)操作,這就會出現幾個問題了,這裡是先更新資料庫,然後對快取操作。但對於快取操作,是更新快取還是刪除快取呢?或者為什麼不是先操作(刪除、更新)快取在更新資料庫呢?
總結一下就是到底先操作快取再運算元據庫,還是先運算元據庫再操作快取?
帶著這幾個問題接著往下講。
首先講一下操作快取,包括兩種:更新快取和刪除快取,如何選擇?
假設都先更新資料庫(因為先操作快取再運算元據庫問題較大,後面會講)
先更新資料庫,再更新快取。
如果兩個請求同時對同一條資料進行修改,那麼可能出現先後順序顛倒,導致快取中的資料是舊的。之後的讀請求讀到的都是舊資料,只有當快取失效後,才能從資料庫中得到正確的值。
先更新資料庫,再刪除快取。
會有這樣一種情況:快取剛好失效,請求B從資料庫中查詢資料,得到舊值。此時請求A更新資料庫,將新值寫入資料庫,並刪除快取。而請求B又將舊值寫入快取中,導致髒資料
從上面看出現髒資料的要求要比更新快取的要求更多,必須滿足以下幾個條件:
前面兩個很好滿足,我們再看看第三點,這個真的會出現嗎?
資料庫在更新時一般是加鎖的,讀操作的速度遠快於寫操作的,所以第三點發生概率極低(當然也可能發生)
注:這裡我其實不是很理解,單純看確實發生概率低,但如果出現網路延遲等情況呢,不也會發生嗎?希望好心人解惑,我反正沒理解。
因此,在選擇刪除快取時,還需要結合其他技術來優化效能和一致性。例如:
對比
在更新快取中, 每次去更新快取,但是快取中的資料不一定會被馬上讀取,這就會導致快取中可能存放了很多不常存取的資料,浪費快取資源。而且很多情況下,寫到快取中的值,並不是與資料庫中的值一一對應的,很有可能是先查詢資料庫,再經過一系列「計算」得出一個值,才把這個值才寫到快取中。
由此可見,這種更新快取的方案,不僅快取利用率不高,還會造成機器效能的浪費。所以我們一般考慮刪除快取
在更新資料時,先將新資料寫入快取(Redis),再將新資料寫入資料庫(MySQL)
但其存在一下問題:
例:使用者修改了自己的暱稱,系統先將新的暱稱寫入快取,然後再更新資料庫。但是在更新資料庫的過程中,發生了網路故障或者資料庫宕機等異常情況,導致資料庫中的暱稱沒有被修改。這樣就會出現快取中的暱稱和資料庫中的暱稱不一致的情況。
例:使用者下單了一個商品,系統先將訂單狀態寫入快取,然後再更新資料庫。但是在更新資料庫的過程中,由於並行量大或者其他原因,導致資料庫的寫入速度慢於快取的寫入速度。這樣就會出現其他請求從快取中讀取到訂單狀態為已支付,而從資料庫中讀取到訂單狀態為未支付的情況。
例:使用者A修改了自己的頭像,並上傳到伺服器上。系統先將新的頭像地址寫入快取,並返回給使用者A顯示。然後再將新的頭像地址更新到資料庫中。但是在這個過程中,使用者B存取了使用者A的個人主頁,並從快取中讀取到了新的頭像地址。由於快取失效策略或者其他原因(比如重啟),導致快取被清空或者過期。這時候使用者B再次存取使用者A 的個人主頁,並從資料庫中讀取到了舊的頭像地址,並將其寫回快取中。這樣就會出現快取中 的頭像地址和 資料庫 中 的頭像地址不一致 的情況。
上面說了一堆,其實總結就是快取更新成功了,資料庫沒更新(更新失敗),導致快取存的是最新值,資料庫存的是舊值。如果快取失效了,就會拿到資料庫中的舊值。
後面我自己也搞疑惑了,既然是因為資料庫更新失敗導致的問題,那我是不是隻要保證資料庫更新成功就可以解決資料不一致的問題,當資料庫更新失敗時,不停的重試更新資料庫,直到資料庫更新完成。
後面發現自己太天真,其中存在很多問題,比如:
所以,這種方法並不是一個很好的解決方案。
當有一個更新操作時,先更新資料庫資料,然後再更新對應的快取資料
但是,這種方案也有一些問題和風險,比如:
因此,在使用更新快取操作時,無論誰先誰後,但凡後者發生異常,就會對業務造成影響。(還是上面那張圖)
那麼如何處理異常情況來保證資料一致性呢
這些問題的源頭都是多執行緒並行所導致的,所以最簡單的方法就是加鎖(分散式鎖)。兩個執行緒要修改同一條資料,每個執行緒在改之前,先去申請分散式鎖,拿到鎖的執行緒才允許更新資料庫和快取,拿不到鎖的執行緒,返回失敗,等待下次重試。這麼做的目的,就是為了只允許一個執行緒去運算元據和快取,避免並行問題。
但加鎖費時費力,肯定不推薦。並且,每次去更新快取,但是快取中的資料不一定會被馬上讀取,這就會導致快取中可能存放了很多不常存取的資料,浪費快取資源。而且很多情況下,寫到快取中的值,並不是與資料庫中的值一一對應的,很有可能是先查詢資料庫,再經過一系列「計算」得出一個值,才把這個值才寫到快取中。
由此可見,這種更新資料庫 + 更新快取的方案,不僅快取利用率不高,還會造成機器效能的浪費。
所以此時我們需要考慮另外一種方案:刪除快取
當有一個更新操作時,先刪除對應的快取資料,然後再更新資料庫資料
但是,這種方案也有一些問題和風險,比如:
當有一個更新操作時,先更新資料庫資料,再刪除快取
上面其實講過了,我再重複一遍吧
會有這樣一種情況:快取剛好失效,請求B從資料庫中查詢資料,得到舊值。此時請求A更新資料庫,將新值寫入資料庫,並刪除快取。而請求B又將舊值寫入快取中,導致髒資料
從上面看出現髒資料的要求要比更新快取的要求更多,必須滿足以下幾個條件:
前面兩個很好滿足,我們再看看第三點,這個真的會出現嗎?
資料庫在更新時一般是加鎖的,讀操作的速度遠快於寫操作的,所以第三點發生概率極低
所以,解決雙寫問題更適合的方法是先更新資料庫,再刪除快取,當然具體場景具體分析,不定說一定就是這個。
講解了這些操作後會出現的問題,那麼為了避免這些問題,如何做呢?
……
下面講幾種常見的方法以保證雙寫一致性
上面也提到過,當第二步操作失敗時,我就重試嘛,儘可能地補救,但重試的成本太大,上面講過就不重複了。
既然重試方法佔用資源,那我就做非同步。在刪除或更新快取時,如果操作失敗,不立即返回錯誤,而是通過一些機制(如訊息佇列、定時任務、訂閱binlog等)來觸發快取的重試操作。這樣可以避免同步重試快取時的效能損耗和阻塞問題,但也可能導致快取和資料庫的資料不一致的時間較長。
使用訊息佇列非同步重試快取的情況是指,當資訊發生變化時,先更新資料庫,然後刪快取,如果刪除成功就皆大歡喜,如果刪除失敗,則將需要刪除的key傳送到訊息佇列。另外有一個消費者執行緒從訊息佇列中獲取要刪除的key,並根據key刪除或更新Redis中的快取。如果操作失敗,則重新傳送到訊息佇列中進行重試。
注:也可以不先嚐試刪除,直接傳送給訊息佇列,讓訊息佇列
舉例來說,假設有一個使用者資訊表,需要將使用者資訊快取在Redis中。如果採用使用訊息佇列非同步重試快取的方案,可以有以下幾個步驟:
使用binlog實現一致性的基本思路是利用binlog紀錄檔來記錄資料庫的變更操作,然後通過主從複製或者增量備份的方式來同步或者恢復資料。
舉例來說,如果我們有一個主資料庫和一個從資料庫,我們可以在主資料庫上開啟binlog紀錄檔,並設定從資料庫作為它的複製節點。這樣,當主資料庫上發生任何變更操作時,它會將對應的binlog紀錄檔傳送給從資料庫,從資料庫則會根據binlog紀錄檔來執行相同的操作,從而保證資料一致性。
另外,如果我們需要恢復某個時間點之前的資料,我們也可以利用binlog紀錄檔來實現。首先,我們需要找到對應時間點之前的最近一個全量備份檔案,並將其恢復到目標資料庫。然後,我們需要找到對應時間點之前的所有增量備份檔案(即binlog紀錄檔檔案),並按照順序將其應用到目標資料庫。這樣,我們就可以恢復出目標時間點之前的資料狀態了。
注:binlog紀錄檔是MySQL的二進位制紀錄檔,它記錄了對資料庫的變更操作,比如插入、更新、刪除等。 binlog紀錄檔有兩個主要作用,一個是主從複製,另一個是增量備份。
主從複製是指在一個主資料庫和一個或多個從資料庫之間實現資料的同步。主資料庫會將自己的binlog紀錄檔傳送給從資料庫,從資料庫則會根據binlog紀錄檔來執行相同的操作,從而保證資料一致性。這樣可以提高資料的可用性和可靠性,也可以實現負載均衡和故障轉移。
增量備份是指在全量備份的基礎上,定期備份資料庫的變更操作。全量備份是指將整個資料庫的資料完整地備份到一個檔案中。增量備份則是指將每次變更操作對應的binlog紀錄檔檔案備份到另一個檔案中。這樣可以減少備份所佔用的空間和時間,也可以實現靈活地恢復資料到任意時間點。
至此,我們可以得出結論,想要保證資料庫和快取一致性,推薦採用「先更新資料庫,再刪除快取」方案,並配合「訊息佇列」或「訂閱變更紀錄檔」的方式來做。
我們重點在將先更新資料庫,在刪除快取。那如果我要先刪除快取,再更新資料庫呢?
回顧之前講的先刪除快取,再更新資料庫,它會出現舊值覆蓋快取的問題,那好辦,我們直接把這個舊值給刪了不就完了嗎,延時雙刪就是這個原理,它的基本思路是:
這樣做的目的是為了防止在更新資料庫後,有其他執行緒讀取到舊的快取資料,並將其寫回快取,導致資料不一致。
舉個例子:假設有一個使用者資訊表,其中有一個欄位是使用者積分。現在有兩個執行緒A和B同時對使用者積分進行操作:
如果使用延時雙刪策略,那麼執行緒A和B的執行過程可能如下:
這樣最終結果就是:資料庫中的使用者積分為1050,快取中沒有該使用者資訊。當下次有請求查詢該使用者資訊時,就會從資料庫中讀取並寫入到快取中。這樣就保證了資料一致性。
延時雙刪適用於高並行場景,特別是對資料的修改操作比較頻繁,而查詢操作比較少的情況。這樣可以減輕資料庫的壓力,提高效能,同時保證資料的最終一致性。延時雙刪也適用於資料庫有主從同步延遲的場景,因為它可以避免在更新資料庫後,從庫還沒有同步完成時,讀取到舊的快取資料,並將其寫回快取。
注: 這個休眠時間 = 讀業務邏輯資料的耗時 + 幾百毫秒。 為了確保讀請求結束,寫請求可以刪除讀請求可能帶來的快取髒資料。
好了,總結一下這篇文章的重點。
Redis與MySQL的雙寫一致性問題是指在使用快取和資料庫同時儲存資料的場景下,如何保證兩者的資料一致性。這個問題主要涉及到以下幾個方面:
為了解決這些問題 , 可以採用以下幾種方法 :
總之,根據場景選擇適合自己的方案
以上就是Redis與MySQL的雙寫一致性問題的詳細內容,更多關於Redis與MySQL的一致性的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45