高併發場景下快取處理思路總結

2021-09-24 05:47:34 字數 4018 閱讀 8289

在實際的開發當中,我們經常需要進行磁碟資料的讀取和搜尋,因此經常會有出現從資料庫讀取資料的場景出現。但是當資料訪問量次數增大的時候,過多的磁碟讀取可能會最終成為整個系統的效能瓶頸,甚至是壓垮整個資料庫,導致系統卡死等嚴重問題。

常規的應用系統中,我們通常會在需要的時候對資料庫進行查詢,因此系統的大致結構如下所示:

當資料量較高的時候,需要減少對於資料庫裡面的磁碟讀寫操作,因此通常都會選擇在業務系統和mysql資料庫之間加入一層快取從而減少對資料庫方面的訪問壓力。

但是很多時候,快取在實際專案中的應用並非這麼簡單。下邊我們來通過幾個比較經典的幾個快取應用場景來列舉一些問題:

1.快取和資料庫之間資料一致性問題

常用於快取處理的機制我總結為了以下幾種:

cache aside, read through, write through, write behind caching

首先來簡單說說cache aside的這種方式:

cache aside模式

這種模式處理快取通常都是先從資料庫快取查詢,如果快取沒有命中則從資料庫中進行查詢。

這裡面會發生的三種情況如下:

快取命中:

當查詢的時候發現快取存在,那麼直接從快取中提取。

快取失效:

當快取沒有資料的時候,則從database裡面讀取源資料,再加入到cache裡面去。

快取更新:

當有新的寫操作去修改database裡面的資料時,需要在寫操作完成之後,讓cache裡面對應的資料失效。

這種cache aside模式通常是我們在實際應用開發中最為常用到的模式。但是並非說這種模式的快取處理就一定能做到完美,

關於這種模式下依然會存在缺陷。比如,乙個是讀操作,但是沒有命中快取,然後就到資料庫中取資料,此時來了乙個寫操作,寫完資料庫後,讓快取失效,然後,之前的那個讀操作再把老的資料放進去,所以,會造成髒資料。

facebook的大牛們也曾經就快取處理這個問題發表過相關的**,鏈結如下:

分布式環境中要想完全的保證資料一致性是一件極為困難的事情,我們只能夠盡可能的減低這種資料不一致性問題產生的情況。

read through模式

read through模式是指應用程式始終從快取中請求資料。 如果快取沒有資料,則它負責使用底層提供程式外掛程式從資料庫中檢索資料。 檢索資料後,快取會自行更新並將資料返回給呼叫應用程式。使用read through 有乙個好處。 我們總是使用key從快取中檢索資料, 呼叫的應用程式不知道資料庫, 由儲存方來負責自己的快取處理,這使**更具可讀性, **更清晰。但是這也有相應的缺陷,開發人員需要給編寫相關的程式外掛程式,增加了開發的難度性。

write through模式

write through模式和read through模式類似,當資料發生更新的時候,先去cache裡面進行更新,如果命中了,則先更新快取再由cache方來更新database。如果沒有命中的話,就直接更新database裡面的資料。

write behind caching模式

write behind caching 這種模式通常是先將資料寫入到快取裡面,然後再非同步的寫入到database中進行資料同步,這樣的設計既可以直接的減少我們對於資料的database裡面的直接訪問,降低壓力,同時對於database的多次修改可以進行合併操作,極大的提公升了系統的承載能力。

但是這種模式處理快取資料具有一定的風險性,例如說當cache機器出現宕機的時候,資料會有丟失的可能。

2.快取穿透問題

在高併發的場景中,快取穿透是乙個經常都會遇到的問題。

什麼是快取穿透?

大量的請求在快取中沒有查詢到指定的資料,因此需要從資料庫中進行查詢,造成快取穿透。

會造成什麼後果?

大量的請求短時間內湧入到database中進行查詢會增加database的壓力,最終導致database無法承載客戶單請求的壓力,出現宕機卡死等現象。

常用的解決方案通常有以下幾類:

1.空值快取

在某些特定的業務場景中,對於資料的查詢可能會是空的,沒有實際的存在,並且這類資料資訊在短時間進行多次的反覆查詢也不會有變化,那麼整個過程中,多次的請求資料庫操作會顯得有些多餘。不妨可以將這些空值(沒有查詢結果的資料)對應的key儲存在快取中,那麼第二次查詢的時候就不需要再次請求到database那麼麻煩,只需要通過記憶體查詢即可。這樣的做法能夠大大減少對於database的訪問壓力。

2.布隆過濾器

通常對於database裡面的資料的key值可以預先儲存在布隆過濾器裡面去,然後先在布隆過濾器裡面進行過濾,如果發現布隆過濾器中沒有的話,就再去redis裡面進行查詢,如果redis中也沒有資料的話,再去database查詢。這樣可以避免不存在的資料資訊也去往儲存庫中進行查詢情況。

關於布隆過濾器的學習可以參考下我的這篇筆記:

3.快取雪崩場景

什麼是快取雪崩?

當快取伺服器重啟或者大量快取集中在某乙個時間段失效,這樣在失效的時候,也會給後端系統(比如db)帶來很大壓力。

如何避免快取雪崩問題?

1.使用加鎖佇列來應付這種問題。當有多個請求湧入的時候,當快取失效的時候加入一把分布式鎖,只允許搶鎖成功的請求去庫裡面讀取資料然後將其存入快取中,再釋放鎖,讓後續的讀請求從快取中取資料。但是這種做法有一定的弊端,過多的讀請求執行緒堵塞,將機器記憶體佔滿,依然沒有能夠從根本上解決問題。

2.在併發場景發生前,先手動觸發請求,將快取都儲存起來,以減少後期請求對database的第一次查詢的壓力。資料過期時間設定盡量分散開來,不要讓資料出現同一時間段出現快取過期的情況。

3.從快取可用性的角度來思考,避免快取出現單點故障的問題,可以結合使用 主從+哨兵的模式來搭建快取架構,但是這種模式搭建的快取架構有個弊端,就是無法進行快取分片,儲存快取的資料量有限制,因此可以公升級為redis cluster架構來進行優化處理。(需要結合企業實際的經濟實力,畢竟redis cluster的搭建需要更多的機器)

4.ehcache本地快取 + hystrix限流&降級,避免mysql***。

使用 ehcache本地快取的目的也是考慮在 redis cluster 完全不可用的時候,ehcache本地快取還能夠支撐一陣。

使用 hystrix進行限流 & 降級 ,比如一秒來了5000個請求,我們可以設定假設只能有一秒 2000個請求能通過這個元件,那麼其他剩餘的 3000 請求就會走限流邏輯。

然後去呼叫我們自己開發的降級元件(降級),比如設定的一些預設值呀之類的。以此來保護最後的 mysql 不會被大量的請求給打死。

高併發場景下快取處理的一些思路

以下是正文 在實際的開發當中,我們經常需要進行磁碟資料的讀取和搜尋,因此經常會有出現從資料庫讀取資料的場景出現。但是當資料訪問量次數增大的時候,過多的磁碟讀取可能會最終成為整個系統的效能瓶頸,甚至是壓垮整個資料庫,導致系統卡死等嚴重問題。常規的應用系統中,我們通常會在需要的時候對資料庫進行查詢,因此...

高併發場景下快取的常見問題

1快取一致性問題 當資料時效性要求很高時,需要保證快取中的資料與資料庫中的保持一致,而且需要保證快取節點和副本中的資料也保持一致,不能出現差異現象。這就比較依賴快取的過期和更新策略。一般會在資料發生更改的時,主動更新快取中的資料或者移除對應的快取。2快取併發問題 快取過期後將嘗試從後端資料庫獲取資料...

高併發場景下的快取常見的問題

當資料時效性要求很高時,需要保證快取中的資料與資料庫中的保持一致,而且需要保證快取節點和副本中的資料也保持一致,不能出現差異現象。這就比較依賴快取的過期和更新策略。一般會在資料發生更改的時,主動更新快取中的資料或者移除對應的快取。快取過期後將嘗試從後端資料庫獲取資料,這是乙個看似合理的流程。但是,在...