1. 程式人生 > 實用技巧 >redis快取穿透穿透解決方案-布隆過濾器

redis快取穿透穿透解決方案-布隆過濾器

redis快取穿透穿透解決方案-布隆過濾器

我們先來看一段程式碼

 cache_key = "id:1"
 cache_value = 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 的值。

關注我的技術公眾號,每週都有優質技術文章推送。
微信掃一掃下方二維碼即可關注: