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 的值。
关注我的技术公众号,每周都有优质技术文章推送。
微信扫一扫下方二维码即可关注: