首頁技術(shù)文章正文

緩存穿透及解決方案

更新時(shí)間:2020-07-14 來源:黑馬程序員 瀏覽量:

緩存只是為了緩解數(shù)據(jù)庫壓力而添加的一層保護(hù)層,當(dāng)從緩存中查詢不到我們需要的數(shù)據(jù)就要去數(shù)據(jù)庫中查詢了。如果被黑客利用,頻繁去訪問緩存中沒有的數(shù)據(jù),那么緩存就失去了存在的意義,瞬間所有請求的壓力都落在了數(shù)據(jù)庫上,這樣會(huì)導(dǎo)致數(shù)據(jù)庫連接異常。

針對緩存穿透的常見解決方案有以下兩種:

方案1: 對于數(shù)據(jù)庫中不存在的數(shù)據(jù), 也對其在緩存中設(shè)置默認(rèn)值Null,為避免占用資源,一般過期時(shí)間會(huì)比較短;

方案2: 可以設(shè)置一些過濾規(guī)則, 如布隆過濾器

方案1:相對簡單, 但是也容易破解, 比如 攻擊者通過分析數(shù)據(jù)格式, 不重復(fù)的請求數(shù)據(jù)庫不存在數(shù)據(jù), 那這樣方案1就等于失效的. 相對而言, 方案2則更加穩(wěn)定, 接下來就主要講解一下方案2的實(shí)現(xiàn)方式。

1594722461371_緩存穿透01.jpg


方案2的設(shè)計(jì)思路是通過設(shè)置過濾規(guī)則, 在數(shù)據(jù)庫查詢之前將數(shù)據(jù)進(jìn)行過濾, 如果發(fā)現(xiàn)數(shù)據(jù)不存在, 則不再進(jìn)行數(shù)據(jù)庫查詢, 以此來減小數(shù)據(jù)庫的訪問壓力。

方案2中過濾規(guī)則目前主流的一種的載體就是布隆過濾器. 布隆過濾器是一種概率型數(shù)據(jù)結(jié)構(gòu),特點(diǎn)是高效地插入和查詢,可以用來告訴你 “某樣?xùn)|西一定不存在或者可能存在”.

相比于傳統(tǒng)的 List、Set、Map 等數(shù)據(jù)結(jié)構(gòu),布隆過濾器是一個(gè)bit數(shù)組, 它更高效、占用空間更少,但是缺點(diǎn)是其返回的結(jié)果是概率性的,而不是確切的。

1594722485580_緩存穿透02.jpg


如果我們要映射一個(gè)值到布隆過濾器中,我們需要使用多個(gè)不同的哈希函數(shù)生成多個(gè)哈希值,并對每個(gè)生成的哈希值指向的 bit 位置 1,例如針對值 “zhangsan” 和三個(gè)不同的哈希函數(shù)分別生成了哈希值 1、4、7

1594722507245_緩存穿透03.jpg


我們現(xiàn)在再存一個(gè)值 “l(fā)isi”,如果哈希函數(shù)返回 4、5、8 的話,圖繼續(xù)變?yōu)椋?br/>

1594722544253_緩存穿透04.jpg


當(dāng)我們想要判斷布隆過濾器是否記錄了某個(gè)數(shù)據(jù)時(shí),布隆過濾器會(huì)先對該數(shù)據(jù)進(jìn)行同樣的哈希處理, 比如 “wangwu”的哈希函數(shù)返回了 2、5、8三個(gè)值,結(jié)果我們發(fā)現(xiàn) 2 這個(gè) bit 位上的值為 0,說明沒有任何一個(gè)值映射到這個(gè) bit 位上,因此我們可以很確定地說 “wangwu” 這個(gè)數(shù)據(jù)不存在。

但是同時(shí)我們會(huì)發(fā)現(xiàn),4 這個(gè) bit 位由于”zhangsan”和”lisi”的哈希函數(shù)都返回了這個(gè) bit 位,因此它被覆蓋了。那么隨著布隆過濾器保存的數(shù)據(jù)不斷增多, 重復(fù)的概率就會(huì)不斷增大, 所以當(dāng)我們過濾某個(gè)數(shù)據(jù)時(shí), 如果發(fā)現(xiàn)其三個(gè)哈希值都在過濾器中進(jìn)行了記錄, 那么也只能說明過濾器中可能包含了該數(shù)據(jù), 并不能絕對肯定, 因?yàn)榭赡苁瞧渌麛?shù)據(jù)的哈希值對結(jié)果產(chǎn)生了影響.這也就解釋了上文所說的 布隆過濾器只能說明“某樣?xùn)|西一定不存在或者可能存在”.至于為什么采用三種不同的哈希函數(shù)取值, 因?yàn)槿齻€(gè)哈希值只要有一個(gè)不存在就說明數(shù)據(jù)一定不在過濾器中, 這樣做是可以減小因哈希碰撞(兩個(gè)數(shù)據(jù)的哈希值相同)產(chǎn)生的錯(cuò)誤概率.

布隆過濾器在很多語言中都有封裝的工具包, 下邊以python的工具包pybloomfiltermmap3 為例演示一下代碼:

import pybloomfilter

 

# 創(chuàng)建過濾器(數(shù)據(jù)容量, 錯(cuò)誤率, 存儲(chǔ)文件)   錯(cuò)誤率越低, 文件越大

filter = pybloomfilter.BloomFilter(1000000, 0.01, 'words.bloom')

 

# 添加數(shù)據(jù)

filter.update(('bj', 'sh', 'gz'))

 

# 判斷是否包含

if 'bj' in filter:

    print('包含')

else:

     print('不包含')


猜你喜歡:

python培訓(xùn)課程

分享到:
在線咨詢 我要報(bào)名
和我們在線交談!