Redis布隆过滤器的原理和用法详解

Redis布隆过滤器的原理和用法详解

缓存穿透

我举个蘑菇博客中的案例来说,我现在有一个博客详情页,然后博客详情页中的内容假设是存储在Redis中的,然后通过博客的Uid进行获取,正常的情况是:用户进入博客详情页,然后通过uid获取redis中缓存的文章详情,如果有内容就直接访问,如果不存在内容,那么需要访问数据库,然后从数据库中查询我们的博客详情后,然后在存储到redis中,最后在把数据返回给我们的页面。

但是可能存在一些非法用户,他可能会模拟出很多不存在的key,然后通过该key去请求后台,首先redis的缓存没有命中,那么就去请求数据库,最后数据库没有查询出该内容,这样很多个非法的请求直接打在数据库中,可能会导致数据库直接宕机,无法对外提供服务。这就是我们所说的缓存穿透问题

简单的解决方法

针对这个情况,我们有一种简单的解决方法就是,在数据库没有查询该条数据的时候,我们让该key缓存一个 空数据,这样用户再次以该key请求后台的时候,会直接返回null,避免了再次请求数据库。

布隆过滤器

什么是布隆过滤器?

布隆过滤器的巨大作用 ,就是能够迅速判断一个元素是否存在一个集合中。因此次他有如下几个使用场景

  • 网站爬虫对URL的去重,避免爬取相同的URL
  • 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否是垃圾邮件(同理,垃圾短信)
  • 缓存穿透,将所有可能的数据缓存放到布隆过滤器中,当黑客访问不存在的缓存时,迅速返回避免缓存以及DB挂掉。

原理

布隆过滤器其内部维护了一个全为0的bit数组,需要说明的是,布隆过滤器有一个误判的概念,误判率越低,则数组越长,所占空间越大。误判率越高则数组越小,所占的空间多少。

假设,根据误判率,我们生成一个10位的bit数组,以及2个hash函数 f1 和 f2,如下图所示:生成的数组的位数 和 hash函数的数量,我们不用去关心如何生成的,这是有数学论文进行验证。

在这里插入图片描述

然后我们输入一个集合,集合中包含 N1 和 N2,我们通过计算 f1(N1) = 2,f2(N1) = 5,则将数组下标为2 和下标为5的位置设置成1,就得到了下图

在这里插入图片描述

同理,我们再次进行计算 N2的值, f1(N2) = 3,f2(N2) = 6。得到如下所示的图

在这里插入图片描述

这个时候,假设我们有第三个数N3过来了,我们需要判断N3是否在集合 [N1,N2]中,我们需要做的操作就是,使用f1 和 f2 计算出数组中的地址

  • 若值恰巧都位于上图的红色位置,我们认为 N3在集合 [N1,N2] 中
  • 若值有一个不位于上图的红色部分,我们认为N3不在集合[N1,N2] 中

这就是布隆过滤器的计算原理

使用

在java中使用布隆过滤器,我们需要首先引入依赖,布隆过滤器拥有Google提供的一个开箱即用的组件,来帮助我们实现布隆过滤器,其实布隆过滤器的核心思想其实并不难,难的是在于如何设计随机映射函数,到底映射几次,二进制向量设置多少比较合适。

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>     
        <artifactId>guava</artifactId>      
        <version>22.0</version>
    </dependency>
</dependencies>

然后我们编写代码,测试某元素是否存在于百万元素集合中

package main

import (
	"fmt"
	"github.com/ricoberger/gobloom"
)

func main() {
	size := 1000000 // 预计要插入多少数据
	fpp := 0.01     // 期望的误判率

	// 创建Bloom Filter
	bloomFilter := gobloom.NewBloomFilter(size, fpp)

	// 插入数据
	for i := 0; i < size; i++ {
		bloomFilter.Add([]byte(fmt.Sprintf("%d", i)))
	}

	count := 0
	// 测试误判
	for i := size; i < 2*size; i++ {
		if bloomFilter.MightContain([]byte(fmt.Sprintf("%d", i))) {
			count++
			fmt.Println(i, "误判了")
		}
	}

	fmt.Println("总共的误判数:", count)
}

代码分析

上面的代码中,我们创建了一个布隆过滤器,其中有两个重要的参数,分别是我们要预计插入的数据和我们所期望的误判率,误判率率不能为0。

我们首先向布隆过滤器中插入 0 ~ 100万条数据,然后在用 100万 ~ 200万的数据进行测试

我们输出结果,查看一下误判率

1999501误判了
1999567误判了
1999640误判了
1999697误判了
1999827误判了
1999942误判了
总共的误判数:10314

现在有100万不存在的数据,误判了10314次,我们计算一下误判率

10314 / 1000000 = 0.010314

和我们之前定义的误判率为0.01相差无几

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Redis布隆过滤器是一种基于Redis的数据结构,用于快速判断一个元素是否存在于一个集合中。Redis布隆过滤器模块在4.0版本中引入,可以通过加载模块的方式来使用。 布隆过滤器的优点是它可以高效地判断一个元素是否存在于集合中,并且具有空间效率高和查询速度快的特点。然而,布隆过滤器也有一些缺点,例如可能会有一定的误判率,并且无法删除已经添加的元素。 使用Redis布隆过滤器需要在Redis中配置布隆过滤器模块。在Redis 4.0及以上版本中,可以通过加载模块的方式来使用布隆过滤器。具体的操作可以参考Redis的官方文档。 为了使用Redis布隆过滤器,你需要使用Redis的命令来增加元素、查询元素和删除元素。可以通过加载Redisson依赖,并编写相应的代码来测试布隆过滤器的使用。 总结来说,Redis布隆过滤器是一种在分布式场景下使用的高效数据结构,可以帮助我们快速判断一个元素是否存在于一个集合中。通过加载Redis布隆过滤器模块,并使用相应的命令,我们可以方便地使用Redis布隆过滤器来进行元素的增删查操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Redis-布隆过滤器(Bloom Filter)详解](https://blog.csdn.net/wuhuayangs/article/details/121830094)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Redis布隆过滤器(Bloom Filter)](https://blog.csdn.net/zhangwei_david/article/details/125685569)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少林码僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值