关于redis:redis缓存穿透穿透解决方案布隆过滤器

35次阅读

共计 2602 个字符,预计需要花费 7 分钟才能阅读完成。

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) 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 的值。

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

正文完
 0