更新時間:2020年07月29日16時19分 來源:傳智播客 瀏覽次數:
緩存只是為了緩解數據庫壓力而添加的一層保護層,當從緩存中查詢不到我們需要的數據就要去數據庫中查詢了。如果被黑客利用,頻繁去訪問緩存中沒有的數據,那么緩存就失去了存在的意義,瞬間所有請求的壓力都落在了數據庫上,這樣會導致數據庫連接異常。
針對緩存穿透的常見解決方案有以下兩種:
方案1: 對于數據庫中不存在的數據, 也對其在緩存中設置默認值Null,為避免占用資源,一般過期時間會比較短;
方案2: 可以設置一些過濾規(guī)則, 如布隆過濾器
方案1:相對簡單, 但是也容易破解, 比如 攻擊者通過分析數據格式, 不重復的請求數據庫不存在數據, 那這樣方案1就等于失效的. 相對而言, 方案2則更加穩(wěn)定, 接下來就主要講解一下方案2的實現方式。
方案2的設計思路是通過設置過濾規(guī)則, 在數據庫查詢之前將數據進行過濾, 如果發(fā)現數據不存在, 則不再進行數據庫查詢, 以此來減小數據庫的訪問壓力。
方案2中過濾規(guī)則目前主流的一種的載體就是布隆過濾器. 布隆過濾器是一種概率型數據結構,特點是高效地插入和查詢,可以用來告訴你 “某樣東西一定不存在或者可能存在”.
相比于傳統的 List、Set、Map 等數據結構,布隆過濾器是一個bit數組, 它更高效、占用空間更少,但是缺點是其返回的結果是概率性的,而不是確切的。
如果我們要映射一個值到布隆過濾器中,我們需要使用多個不同的哈希函數生成多個哈希值,并對每個生成的哈希值指向的 bit 位置 1,例如針對值 “zhangsan” 和三個不同的哈希函數分別生成了哈希值 1、4、7
我們現在再存一個值 “lisi”,如果哈希函數返回 4、5、8 的話,圖繼續(xù)變?yōu)椋?/p>
當我們想要判斷布隆過濾器是否記錄了某個數據時,布隆過濾器會先對該數據進行同樣的哈希處理, 比如 “wangwu”的哈希函數返回了 2、5、8三個值,結果我們發(fā)現 2 這個 bit 位上的值為 0,說明沒有任何一個值映射到這個 bit 位上,因此我們可以很確定地說 “wangwu” 這個數據不存在。
但是同時我們會發(fā)現,4 這個 bit 位由于”zhangsan”和”lisi”的哈希函數都返回了這個 bit 位,因此它被覆蓋了。那么隨著布隆過濾器保存的數據不斷增多, 重復的概率就會不斷增大, 所以當我們過濾某個數據時, 如果發(fā)現其三個哈希值都在過濾器中進行了記錄, 那么也只能說明過濾器中可能包含了該數據, 并不能絕對肯定, 因為可能是其他數據的哈希值對結果產生了影響.這也就解釋了上文所說的 布隆過濾器只能說明“某樣東西一定不存在或者可能存在”.至于為什么采用三種不同的哈希函數取值, 因為三個哈希值只要有一個不存在就說明數據一定不在過濾器中, 這樣做是可以減小因哈希碰撞(兩個數據的哈希值相同)產生的錯誤概率.
布隆過濾器在很多語言中都有封裝的工具包, 下邊以python的工具包pybloomfiltermmap3 為例演示一下代碼:
import pybloomfilter
# 創(chuàng)建過濾器(數據容量, 錯誤率, 存儲文件) 錯誤率越低, 文件越大
filter = pybloomfilter.BloomFilter(1000000, 0.01, 'words.bloom')
# 添加數據
filter.update(('bj', 'sh', 'gz'))
# 判斷是否包含
if 'bj' in filter:
print('包含')
else:
print('不包含')
猜你喜歡:
Python培訓課程