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/ [root@redisbloom-1.1.1]# make [root@redisbloom-1.1.1]# 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) 1127.0.0.1:6379> bf.add users user1  //写入数据user1(integer) 1127.0.0.1:6379> bf.exists users user1  //查问user1存在(integer) 1127.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 的值。

关注我的技术公众号,每周都有优质技术文章推送。
微信扫一扫下方二维码即可关注: