偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

雙寫兜兜轉轉,又回到了串行化的方式

開發(fā) 前端
我們開門見山,這個很好理解,雙寫就是說,一份數據在數據庫存一份,在緩存中也存一份,給緩存一個過期時間,當讀不到緩存時從數據庫讀出來然后寫入緩存。

[[393138]]

本文轉載自微信公眾號「moon聊技術」,作者 moon聊技術。轉載本文請聯系 moon聊技術公眾號。

什么是雙寫?

我們開門見山,這個很好理解,雙寫就是說,一份數據在數據庫存一份,在緩存中也存一份,給緩存一個過期時間,當讀不到緩存時從數據庫讀出來然后寫入緩存。

為什么需要雙寫呢?

當請求量越來越大的時候,系統(tǒng)會慢慢出現瓶頸,由于數據庫的鏈接是有限的,無法支撐較高的QPS,所以我們要想一個辦法分擔數據庫的壓力,于是就有了雙寫,將數據寫入緩存,客戶端讀取數據直接從緩存中讀取,這樣就可以提高系統(tǒng)的性能。

但是如果要使用雙寫,那么不管是先更新緩存還是先更新mysql,總會有時間間隔,那么就要保證你的業(yè)務在一定程度上允許短暫的數據不一致的情況出現,否則,還是不建議使用的.

那么就有人問了?雙寫一定不能保證強一致性嗎?

答案是可以,只要把所有與其相關的讀寫請求用隊列串行化,這樣就可以保證雙寫的強一致性了,但是這樣會極大的降低系統(tǒng)的QPS,非常不推薦這種做法。

既然要雙寫,那么肯定會出現數據庫和緩存數據不一致的情況,要怎樣去避免呢?

雙寫不一致問題要怎么解決

一.先更新數據庫,再更新緩存

這種情況會有什么問題呢?我們看下圖:

首先a先更新數據庫,按照正常流程來走,緊接著要a線程刪除緩存,可是突然后面來了個b線程,并且a線程因為各種業(yè)務原因卡住了,導致b線程先完成了,之后a線程才更新緩存。這時突然有其他線程進來讀數據,就會讀到a的數據,但是按照業(yè)務流程來走,應該讀到b的數據,此時,就出現了數據錯亂的問題。

  • 1.線程a更新數據庫
  • 2.線程b更新數據庫
  • 3.線程b更新緩存
  • 4.線程a更新緩存
  • 5.其他線程讀數據(讀錯了)

到這里我們會發(fā)現,直接更新緩存是有很大的問題的,而且很多時候,在復雜點的緩存場景,緩存不單單是數據庫中直接取出來的值,有可能是聯合其他的很多數據結合計算出來的一個值。

而且可能會有一種場景,我們經常在更新數據庫后直接更新緩存,但是在此之間并沒有緩存被訪問的需求,這樣我們就做了很多無用功,付出了很多代價。

大家應該對單例模式有所了解,其中有一種懶加載的思想,就是說,在你需要的時候再去加載,用在雙寫的情況下非常合適,也就有了下面這種先更新數據庫,再刪除緩存的模式。

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

這種情況又會有什么問題呢?

當然,這還是一種有問題的方案,我們來跟著圖盤一盤。

1:線程a更新數據庫

2:程序掛了,沒來的及刪除緩存

3.其他線程來讀數據(全都是錯的)

這種方案的問題一目了然,只要程序掛了,就會出現數據讀錯的情況,真實的業(yè)務你是應該讀到a線程的值,卻一直在讀之前的值。

那這種方案有沒有優(yōu)化呢?

當然也有了,其實我們可以每次寫入都記錄日志,然后修改結束后也記錄日志,通過日志狀態(tài)來判斷是否寫入成功,

  • 如果沒有寫入成功后續(xù)并且沒有新的寫入請求,就補寫,
  • 否則不做處理。

但是這種情況也會出現不一致的問題,就是如果寫數據庫程序斷了,到下次恢復數據之前這段時間,還會出現數據不一致的情況。

并且如果是頻繁寫入的情況,很有可能日志機制沒有發(fā)揮作用,就有新數據寫入覆蓋,并且日志系統(tǒng)還要占用額外的資源。

我懂了!應該先刪除緩存再更新數據庫,這樣就可以了!

三.先刪除緩存 再更新數據庫

來來來,繼續(xù)貼圖,是不是很熟悉?

這種方案會有問題嗎??當然有,繼續(xù)盤道:

  • 1:線程a刪除緩存
  • 2:線程b刪除緩存
  • 3:線程a卡了
  • 4:線程b更新數據庫
  • 5:線程a更新數據
  • 6:其他線程讀數據,讀到了a的(又錯了)

完了,這種情況居然也有問題,線程a到底行不行,每次都是你出事。

這種情況中間會有一段數據亂掉,但是隨著下次的更新數據還是會恢復正確。

難道終極方案是先刪除緩存,再更新數據庫,再更新緩存??

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

繼續(xù)貼圖

  • 1.線程a刪除緩存
  • 2.其他線程讀取數據,讀到的是a之前的數據
  • 3.線程a更新數據庫
  • 4.線程a刪除緩存
  • 5.其他線程設置緩存數據,是a之前的數據(此時應該是a的)

大家是不是又發(fā)現了,這種設計方案還是會有問題的,直到下次數據更新才有可能將數據恢復正確。

來吧,最后一種大家經常討論的延時雙刪方案,我們一起盤一盤。

五.延時雙刪

go on

  • 1.先刪除緩存
  • 2.再寫數據庫
  • 3.休眠一段時間(根據具體的業(yè)務時間來定)
  • 4.再次刪除緩存

這里加了一個延時的操作,目的是確保 修改數據庫 -> 清空緩存前,其他事務的更改緩存操作已經執(zhí)行完。

所有的寫操作以數據庫為準,只要到達緩存過期時間,則后面的讀請求自然會從數據庫中讀取新值然后回填緩存。

但這其中難免還是會大量的查詢到舊緩存數據的,因為延時時間是根據業(yè)務自己定義的,時間太長和太短在高并發(fā)情況下都會有查詢到臟數據的情況產生。

這樣最差的情況就是在超時時間內數據存在不一致。

結語

到這里大家應該會發(fā)現,除了串行化這種方式以外,其他無論哪種方式大大小小都會有數據不一致的現象發(fā)生,有時為了維護數據一致性問題還要做很多額外很重的操作,比如加一些日志來做狀態(tài)處理雙寫問題,具體的方案選擇還是要根據業(yè)務的敏感度來定的。

 

責任編輯:武曉燕 來源: moon聊技術
相關推薦

2009-07-10 09:38:06

Java swing組

2009-11-18 11:05:27

PHP串行化

2009-06-09 16:14:47

Java swing組件串行化

2016-11-17 22:18:31

id串行化服務器

2009-09-11 12:17:59

C#控件屬性

2009-11-02 16:41:55

VB.NET串行化對象

2019-03-25 07:39:35

ID串行化消息順序性高可用

2010-01-12 10:29:51

VB.NET對象串行化

2010-01-06 10:49:54

PHP串行化JSON

2009-11-17 16:24:27

PHP變量串行化

2010-01-14 18:00:07

VB.NET串行化對象

2025-06-19 08:03:03

2010-01-06 10:58:06

建立JavaScrip

2010-01-06 11:05:35

JSON

2021-09-10 09:58:35

AvlBST時間

2017-03-13 16:58:05

戴爾

2022-02-28 21:15:42

火狐火狐瀏覽器瀏覽器

2011-05-18 15:20:13

XML

2018-08-20 16:00:23

MySQL并發(fā)控制MVCC

2023-03-29 08:33:03

倉儲自動化系統(tǒng)
點贊
收藏

51CTO技術棧公眾號