四川省紀(jì)委網(wǎng)站建設(shè)今日武漢最新消息
對(duì)于緩存,我們主要關(guān)心兩個(gè):緩存的命中率,數(shù)據(jù)的一致性。由此又會(huì)有一些緩存引起的問(wèn)題,緩存擊穿、穿透、雪崩。對(duì)于這些問(wèn)題也是我們?cè)谑褂镁彺鏁r(shí)不得不考慮的 。這些問(wèn)題的解決方案也有很多。這里簡(jiǎn)單列舉幾個(gè):
(1)針對(duì)無(wú)效數(shù)據(jù)穿透,多級(jí)攔截:
無(wú)效數(shù)據(jù),空數(shù)據(jù),進(jìn)行多種手段攔截,如布隆過(guò)濾器、業(yè)務(wù)參數(shù)有效性判斷、緩存空值等等。多種手段攔截就是讓流量最后無(wú)法穿透到最薄弱的底層服務(wù)。
(2)針對(duì)高并發(fā)熱點(diǎn)key擊穿,兩階段失效:
對(duì)于高并發(fā)的熱點(diǎn)key,做邏輯和物理兩階段失效策略,邏輯失效前端響應(yīng)仍然立即返回,僅異步排隊(duì)去底層服務(wù)或DB獲取數(shù)據(jù)并刷新緩存。
(3)緩存降級(jí),限流排隊(duì),多級(jí)緩存:
緩存由于各種原因不可用,如果無(wú)任何措施,勢(shì)必會(huì)出現(xiàn)雪崩的現(xiàn)象,為了盡可能保證業(yè)務(wù)服務(wù)可用或者部分可用,則必須對(duì)緩存允許降級(jí),即便緩存中間件連接異常,宕機(jī)等,仍然可以去底層的服務(wù)和DB獲取數(shù)據(jù),常用手段一般是二級(jí)、甚至三級(jí)緩存,最后就是加鎖排隊(duì)訪問(wèn)底層服務(wù)。
(4)失效時(shí)間隨機(jī)
往往熱key都是在同一個(gè)時(shí)間點(diǎn)(短暫的時(shí)間段)創(chuàng)建的,如果固定有效時(shí)長(zhǎng),則失效將在同一個(gè)時(shí)間點(diǎn),當(dāng)失效發(fā)生時(shí),雪崩的可能性很大。在業(yè)務(wù)要求的失效時(shí)間點(diǎn)上,加上隨機(jī)時(shí)長(zhǎng)(范圍),可以分散熱key失效時(shí)間點(diǎn)。
緩存擊穿、穿透和雪崩是與緩存相關(guān)的常見(jiàn)問(wèn)題。它們是在使用緩存時(shí)可能遇到的一些挑戰(zhàn)和風(fēng)險(xiǎn)。下面是對(duì)這些問(wèn)題的解釋以及相應(yīng)的實(shí)際例子:
1.緩存擊穿: 緩存擊穿指的是在緩存中不存在但是頻繁被請(qǐng)求的數(shù)據(jù),導(dǎo)致請(qǐng)求繞過(guò)緩存直接訪問(wèn)數(shù)據(jù)庫(kù)或其他數(shù)據(jù)源,增加了后端負(fù)載。這通常發(fā)生在緩存中的數(shù)據(jù)過(guò)期或被刪除時(shí)。
例子:假設(shè)一個(gè)電子商務(wù)網(wǎng)站的商品詳情頁(yè)被頻繁訪問(wèn),并且每次訪問(wèn)都會(huì)從數(shù)據(jù)庫(kù)中獲取商品信息。如果某個(gè)商品的緩存過(guò)期,而此時(shí)有大量用戶(hù)請(qǐng)求該商品的詳情頁(yè),這些請(qǐng)求將繞過(guò)緩存直接訪問(wèn)數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)負(fù)載過(guò)高。
1.緩存穿透: 緩存穿透指的是請(qǐng)求的數(shù)據(jù)在緩存和數(shù)據(jù)源中都不存在,這將導(dǎo)致每次請(qǐng)求都需要訪問(wèn)數(shù)據(jù)源,增加了后端負(fù)載。這通常是由于惡意或無(wú)效的請(qǐng)求導(dǎo)致的。
例子:假設(shè)一個(gè)新聞網(wǎng)站允許用戶(hù)根據(jù)新聞ID獲取新聞內(nèi)容。如果有惡意用戶(hù)通過(guò)構(gòu)造不存在的新聞ID來(lái)頻繁請(qǐng)求新聞內(nèi)容,而這些請(qǐng)求都無(wú)法命中緩存或找到相應(yīng)的數(shù)據(jù),每次請(qǐng)求都需要訪問(wèn)數(shù)據(jù)庫(kù),造成了無(wú)謂的資源浪費(fèi)。
1.緩存雪崩: 緩存雪崩指的是緩存中大量的數(shù)據(jù)同時(shí)過(guò)期或失效,導(dǎo)致大量請(qǐng)求直接訪問(wèn)數(shù)據(jù)源,造成后端系統(tǒng)的壓力過(guò)大甚至崩潰。
例子:假設(shè)一個(gè)電商網(wǎng)站的商品列表頁(yè)的緩存時(shí)間都設(shè)置為相同的時(shí)間,當(dāng)緩存過(guò)期時(shí),大量用戶(hù)同時(shí)請(qǐng)求商品列表頁(yè),這些請(qǐng)求將直接訪問(wèn)數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)負(fù)載激增,甚至可能導(dǎo)致數(shù)據(jù)庫(kù)崩潰。
為了解決這些問(wèn)題,可以采取以下措施:
?對(duì)于緩存擊穿,可以通過(guò)在緩存中設(shè)置短暫的過(guò)期時(shí)間或使用互斥鎖的方式來(lái)避免。當(dāng)某個(gè)數(shù)據(jù)過(guò)期時(shí),只允許一個(gè)請(qǐng)求去重新加載數(shù)據(jù)到緩存中,其他請(qǐng)求等待。
?對(duì)于緩存穿透,可以在緩存中設(shè)置一個(gè)特殊的值,表示數(shù)據(jù)不存在,并將該值緩存一段時(shí)間。這樣,當(dāng)惡意請(qǐng)求到來(lái)時(shí),可以直接從緩存中返回這個(gè)特殊值,而不需要訪問(wèn)數(shù)據(jù)源。
?對(duì)于緩存雪崩,可以采用多級(jí)緩存、緩存數(shù)據(jù)的不同過(guò)期時(shí)間或使用熱點(diǎn)數(shù)據(jù)預(yù)加載等策略。這樣可以減少緩存同時(shí)失效的概率,分散請(qǐng)求對(duì)后端系統(tǒng)的沖擊。
需要根據(jù)具體情況和使用的緩存系統(tǒng)來(lái)選擇合適的解決方案。
布隆過(guò)濾器(Bloom Filter)
是一種空間效率很高的概率型數(shù)據(jù)結(jié)構(gòu),用于判斷一個(gè)元素是否屬于一個(gè)集合。它通過(guò)使用多個(gè)哈希函數(shù)和位數(shù)組來(lái)判斷元素是否存在,可以快速地進(jìn)行查找和過(guò)濾。
以下是一個(gè)簡(jiǎn)單的布隆過(guò)濾器的示例代碼:
python
CopyReplace
import mmh3from bitarray import bitarray
classBloomFilter:def__init__(self, size, hash_functions):self.size = sizeself.hash_functions = hash_functionsself.bit_array = bitarray(size)self.bit_array.setall(0)defadd(self, item):for fn in self.hash_functions:index = mmh3.hash(item, fn)% self.sizeself.bit_array[index]=1defcontains(self, item):for fn in self.hash_functions:index = mmh3.hash(item, fn)% self.sizeif self.bit_array[index]==0:returnFalsereturnTrue
# 創(chuàng)建一個(gè)布隆過(guò)濾器實(shí)例
size =10 # 位數(shù)組的大小
hash_functions =[1,2,3] # 哈希函數(shù)的數(shù)量
bloom_filter = BloomFilter(size, hash_functions)
# 添加元素到布隆過(guò)濾器
bloom_filter.add("apple")
bloom_filter.add("banana")
bloom_filter.add("orange")
# 檢查元素是否存在于布隆過(guò)濾器print(bloom_filter.contains("apple")) # 輸出: Trueprint(bloom_filter.contains("grape")) # 輸出: False
在這個(gè)示例中,BloomFilter
類(lèi)表示布隆過(guò)濾器。在初始化過(guò)程中,我們指定了位數(shù)組的大小和哈希函數(shù)的數(shù)量。bitarray
庫(kù)用于創(chuàng)建位數(shù)組,并使用mmh3
哈希函數(shù)庫(kù)來(lái)生成哈希值。
add
方法用于將元素添加到布隆過(guò)濾器中。它使用每個(gè)哈希函數(shù)對(duì)元素進(jìn)行哈希,并將對(duì)應(yīng)的位數(shù)組位置置為1。
contains
方法用于檢查元素是否存在于布隆過(guò)濾器中。它使用每個(gè)哈希函數(shù)對(duì)元素進(jìn)行哈希,并檢查對(duì)應(yīng)的位數(shù)組位置是否為1。如果有任何一個(gè)位置為0,則說(shuō)明元素不在布隆過(guò)濾器中。
在示例中,我們創(chuàng)建了一個(gè)布隆過(guò)濾器實(shí)例,添加了幾個(gè)元素,并檢查了其中的一些元素是否存在于布隆過(guò)濾器中。
需要注意的是,布隆過(guò)濾器存在一定的誤判率(False Positive),即可能會(huì)判斷某個(gè)元素存在于集合中,但實(shí)際上并不存在。因此,在使用布隆過(guò)濾器時(shí),需要根據(jù)具體應(yīng)用場(chǎng)景和數(shù)據(jù)量來(lái)選擇合適的位數(shù)組大小和哈希函數(shù)數(shù)量,以控制誤判率。