redis快取穿透穿透解決方案-布隆過濾器
我們先來看一段代碼
cache_key = "id:1"
cache_value = https://www.cnblogs.com/xuehao/p/GetValueFromRedis(cache_key); //判斷快取是否有資料
if cache_value != nil{ //如果有 直接回傳資料
return cache_value
}
db_value = GetValueFromDb(cache_key) // 從資料庫中查詢資料
if db_value == nil{
return db_value
}
expire_time = 300
SetRedisValue(cache_key, db_value, expire_time) //將資料庫的結果更新到快取中,并直接回傳結果
return db_value
相信絕大多數同學都是這么處理請求的,這樣用redis能夠給mysql抵擋住大部分的請求,其實這樣是存在一定的問題的
問題1
我在請求的時候,用id=-1來請求
id=-1這條記錄在資料庫中是不存在的,當然對應的redis中也是沒有的,那么就需要去請求資料庫然后把資料寫入到redis中,這樣就會造成沒有必要的資料庫請求,一兩個請求無所謂,但是如果從-∞到-1 無限的高頻率的請求,就會給線上造成很大的壓力,
針對問題1的解決方案
我們可以通程序式來限制id的合法性,判斷id<1的情況都直接在介面層面攔截,這個方式的確可以解決上面說的那種情況,但是咱們接下來往下看
問題2
比如現在資料庫id的最大值為1000,我們用比1000大的數字去請求
這種情況原理和問題1是一樣的,這次我們就沒法通過引數判斷來攔截住請求了,所以我們就得用接下來一種經典的方式,布隆過濾器
布隆過濾器其實就是一種比較巧妙的概率型資料結構,它可以告訴你某種東西一定不存在或者可能存在,從而達到對臟資料過濾的效果,他存在的位置如圖

其實對布隆過濾器比較陌生的同學可以先想想,作為一個過濾器需要滿足什么條件?
- 速度得快,得從記憶體查,如果從硬碟查的話還不如直接查資料庫
- 因為過濾器里面得存入資料庫所有的資料,所以記憶體勢必是比較緊張的,所以記憶體要做到絕對的節省,說到節省記憶體,大家應該很容易能想到 redis里面的setbit操作
布隆過濾器的實作

寫入程序
- 通過bit陣列來標識資料
- 比如id=10的資料,通過hash演算法算出來結果為1
- 把bit陣列下表為1的位置的值標記為1
查詢程序
- 將id=10做hash運算,得到結果1
- 看bit陣列下表為1的資料標識為1,則說明資料存在
其實我們看上面的演算法是存在一定的問題的
1:只要是hash運算,就會存在hash碰撞問題,比如id=10 和id=100可能經過hash運算之后結果都為1,那么id=10寫入之后查詢id=100是否存在會誤判為id=100也存在
2:當bit陣列滿了之后,查詢的錯誤率肯定是百分之百,因為每個資料都存在
這些其實都是導致錯誤率的原因,錯誤率是不可能避免的,但是咱們可以減少錯誤率,減少錯誤率的方法有兩個
1:加大bit陣列的長度,對于bit陣列的長度的增加是不用擔心的,因為是bit操作,所以可以加到很大的值
2:增加hash函式的個數,hash函式的個數增加了,說明標識一個陣列需要的位置就會變多,這樣會降低發生hash碰撞的概率,但是hash的函式也不是越多越好,需要參照陣列的長度來定
hash錯誤率:
布隆演算法說資料存在,那么實際有可能不存在
如果資料不存在,那么一定不存在
布隆過濾器redis中的使用方法
1.下載redisbloom插件(redis官網下載即可)
wget https://github.com/RedisLabsModules/rebloom/archive/v1.1.1.tar.gz
2:解壓并安裝,生成.so檔案
[root@redis]# tar -zxvf v1.1.1.tar.gz
[root@redis]# cd Redisbloom-1.1.1/
[[email protected]]# make
[[email protected]]# ls
contrib Dockerfile docs LICENSE Makefile mkdocs.yml ramp.yml README.md rebloom.so src tests
3:在redis組態檔(redis.conf)中加入該模塊即可
[root@redis]# vim redis.conf
#####################MODULES################# # Load modules at startup. If the server is not able to load modules
# it will abort. It is possible to use multiple loadmodule directives.
loadmodule /usr/local/redis/redisbloom-1.1.1/rebloom.so
4:重新啟動redis
redis-server ./redis.conf
5:測驗安裝是否成功
127.0.0.1:6379> bf.add users user2 //寫入資料user2
(integer) 1
127.0.0.1:6379> bf.add users user1 //寫入資料user1
(integer) 1
127.0.0.1:6379> bf.exists users user1 //查詢user1存在
(integer) 1
127.0.0.1:6379> bf.exists users user3 //查詢user3不存在
(integer) 0
上面說過布隆過濾器存在誤判的情況,在 redis 中有兩個值決定布隆過濾器的準確率:
- error_rate :允許布隆過濾器的錯誤率,這個值越低過濾器的位陣列的大小越大,占用空間也就越大,
- initial_size :布隆過濾器可以儲存的元素個數,當實際存盤的元素個數超過這個值之后,過濾器的準確率會下降,
redis 中有一個命令可以來設定這兩個值:
bf.reserve users 0.01 100
三個引數的含義:
第一個值是過濾器的名字,
第二個值為 error_rate 的值,
第三個值為 initial_size 的值,
關注我的技術公眾號,每周都有優質技術文章推送,
微信掃一掃下方二維碼即可關注:
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/192045.html
標籤:其它

