基于Redisson的Redis结合布隆过滤器使用

一、场景

  • 缓存穿透问题

一般情况下,先查询Redis缓存,如果Redis中没有,再查询MySQL。当某一时刻访问redis的大量key都在redis中不存在时,所有查询都要访问数据库,造成数据库压力顿时上升,这就是缓存穿透。八股文背多了都知道:在Redis前面添加一层布隆过滤器,请求先在布隆过滤器中判断,如果布隆过滤器不存在时,直接返回,不再访问Redis和MySQL。如果布隆过滤器中存在时,再访问Redis,再访问数据库。完美解决缓存穿透问题。说白了:布隆过滤器就是redis的缓存

在这里插入图片描述

除此之外还有以下场景:

  • 黑名单 :如果黑名单非常大,上千万了,存放起来很耗费空间,在布隆过滤器中实现黑名单功能,是一个很好的选择。
  • 网页爬虫对URL的去重,避免爬取相同的URL地址

二、布隆过滤器

  1. 布隆过滤器BloomFilter是什么

布隆过滤器BloomFilter是一种专门用来解决去重问题的高级数据结果。实质就是一个大型位数组和几个不同的无偏hash函数,无偏表示分布均匀。由一个初值为零的bit数组和多个哈希函数组成,用来判断某个数据是否存在,它和HyperLogLog一样,不是那么的精准,存在一定的误判概率

  1. 布隆过滤器BloomFilter能干嘛?
    在这里插入图片描述
  • 高效地插入和查询,占用空间少,返回的结果是不确定的,一个元素如果判断结果为存在,它不一定存在;不存在时,一定不存在。 查询某个变量的时候我们只要看看这些点是不是都是 1, 就可以大概率知道集合中有没有它了。如果这些点, 有任何一个为零则被查询变量一定不在, 如果都是 1,则被查询变量很 可能存在。 为什么说是可能存在,而不是一定存在呢? 那是因为映射函数本身就是散列函数,散列函数是会有碰撞的

  • 布隆过滤器BloomFilter只能添加元素,不能删除元素。这和上面提到的hashcode判定原理是一样的,相同hashcode的字符串会存储在一个index,删除时,是将某个index移除,此时,就可能移除拥有相同hashcode的不同字符串

三、实现原理和数据结构

  1. 初始化

布隆过滤器 本质上 是由长度为 m 的位向量或位列表(仅包含 0 或 1 位值的列表)组成,最初所有的值均设置为

在这里插入图片描述

  1. 添加

当我们向布隆过滤器中添加数据时,为了尽量地址不冲突, 会使用多个 hash 函数对 key 进行运算 ,算得一个下标索引值,然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。 例如,我们添加一个字符串wmyskxz:

在这里插入图片描述

  1. 判断是否存在

向布隆过滤器查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算 ,查看对应的位置是否都为 1, 只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在; 如果这几个位置全都是 1,那么说明极有可能存在; 因为这些位置的 1 可能是因为其他的 key 存在导致的,也就是前面说过的hash冲突。

例子:我们在 add 了字符串wmyskxz数据之后,很明显下面1/3/5 这几个位置的 1 是因为第一次添加的 wmyskxz 而导致的; 此时我们查询一个没添加过的不存在的字符串inexistent-key,它有可能计算后坑位也是1/3/5 ,这就是误判了。
在这里插入图片描述

  1. 误判率,为什么不能删除元素?

布隆过滤器的误判是指多个输入经过哈希之后在相同的bit位置1了,这样就无法判断究竟是哪个输入产生的, 因此误判的根源在于相同的 bit 位被多次映射且置 1。 这种情况也造成了布隆过滤器的删除问题,因为布隆过滤器的每一个 bit 并不是独占的,很有可能多个元素 共享了某一位 。 如果我们直接删除这一位的话,会影响其他的元素。

  1. 如何解决不能删除
  • 布谷鸟过滤器

为了解决布隆过滤器不能删除元素的问题 ,布谷鸟过滤器横空出世。论文《Cuckoo Filter:Better Than Bloom》
作者将布谷鸟过滤器和布隆过滤器进行了深入的对比。相比布谷鸟过滤器而言布隆过滤器有以下不足: 查询性能弱、空间利用效率低、不支持反向操作(删除)以及不支持计数

  1. 常用命令

在Redis中,布隆过滤器有两个基本命令,分别是:

  • bf.add:添加元素到布隆过滤器中,类似于集合的sadd命令,不过bf.add命令只能一次添加一个元素,如果想一次添加多个元素,可以使用bf.madd命令
  • bf.exists:判断某个元素是否在过滤器中,类似于集合的sismember命令,不过bf.exists命令只能一次查询一个元素,如果想一次查询多个元素,可以使用bf.mexists命令

四、Redis使用布隆过滤器

  1. redis版本:推荐版本6.x,最低4.x版本
  2. 下载布隆过滤器插件(版本自选)
wget https://github.com/RedisLabsModules/rebloom/archive/v2.2.6.tar.gz
  1. 解压,编译,得到.so
  1. tar -zxvf v2.2.6.tar.gz
  2. cd RedisBloom-2.2.6/
  3. make在这里插入图片描述
  1. Redis配置文件修改

在redis.conf配置文件中加入如RedisBloom的redisbloom.so文件的地址

loadmodule /usr/local/soft/RedisBloom-2.2.6/redisbloom.so

如果是集群则每个配置文件中都需要加入redisbloom.so文件的地址
在这里插入图片描述

  1. 添加完成后需要重启redis
  2. 集成布隆过滤器的redis项目:Rebloom插件布隆过滤器,有原生镜像可以直接使用

五、代码层面调用(java)

  • 基于redisson实现
package com.ruoyi.demo;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;

import java.util.concurrent.TimeUnit;

public class RedissonBloomFilterDemo {
    public static final int _1W = 10000;

    //布隆过滤器里预计要插入多少数据
    public static int size = 100 * _1W;
    //误判率,它越小误判的个数也就越少
    public static double fpp = 0.03;

    static RedissonClient redissonClient = null;//jedis
    static RBloomFilter rBloomFilter = null;//redis版内置的布隆过滤器

    static {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.1.8:6379").setPassword("cxm199610133914")
            .setDatabase(2);
        //构造redisson
        redissonClient = Redisson.create(config);
        //通过redisson构造rBloomFilter
        rBloomFilter = redissonClient.getBloomFilter("phoneListBloomFilter",new StringCodec());

        rBloomFilter.tryInit(size,fpp);

        // 1测试  布隆过滤器有+redis有
        rBloomFilter.add("10086");
        redissonClient.getBucket("10086",new StringCodec()).set("chinamobile10086");

        // 2测试  布隆过滤器有+redis无
        rBloomFilter.add("10087");

        //3 测试 ,布隆过滤器无+redis无

    }

    private static String getPhoneListById(String IDNumber) {
        String result = null;

        if (IDNumber == null) {
            return null;
        }
        //1 先去布隆过滤器里面查询
        if (rBloomFilter.contains(IDNumber)) {
            //2 布隆过滤器里有,再去redis里面查询
            RBucket<String> rBucket = redissonClient.getBucket(IDNumber, new StringCodec());
            result = rBucket.get();
            if(result != null) {
                return "i come from redis: "+result;
            }else{
                result = getPhoneListByMySQL(IDNumber);
                if (result == null) {
                    return null;
                }
                // 重新将数据更新回redis
                redissonClient.getBucket(IDNumber, new StringCodec()).set(result);
            }
            return "i come from mysql: "+result;
        }
        return result;
    }

    private static String getPhoneListByMySQL(String IDNumber) {
        return "chinamobile"+IDNumber;
    }

    public static void main(String[] args) {
        //String phoneListById = getPhoneListById("10086");
        //String phoneListById = getPhoneListById("10087"); //请测试执行2次
        String phoneListById = getPhoneListById("10088");
        System.out.println("------查询出来的结果: "+phoneListById);

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(1);

        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        redissonClient.shutdown();
    }
}

参考文章
参考文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/41371.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

成为一个年薪30W+的DFT工程师是一种什么体验?

一直以来&#xff0c;DFT都是数字IC设计行业中相对神秘的一个岗位。 你说他重要吧&#xff0c;并不是所有芯片设计公司都有这个岗位&#xff0c;你说他不重要吧&#xff0c;但凡芯片产品达到一定规模后&#xff0c;就必须设置DFT部门。 一、什么是DFT&#xff1f; DFT&#x…

【分布式应用】ceph分布式存储

目录 一、存储基础1.1单机存储设备1.2单机存储的问题1.3分布式存储的类型 二、Ceph简介2.1Ceph 优势2.2Ceph 架构2.3Ceph核心组件OSD&#xff08;Object Storage Daemon&#xff0c;守护进程 ceph-osd&#xff09;PG&#xff08;Placement Group 归置组&#xff09;PoolMonitor…

SpringBoot错误: 找不到或无法加载主类

1.一般出现这种情况都是配置文件application.properties出现的问题 2.可以尝试 maven clean install 以及rebuild project 3.删除项目里.idea文件 重新导入至IDEA编辑器 选择Maven项目 配置好maven.xml 后重新导入

解决GitHub下载速度太慢问题的方法汇总(持续更新,建议收藏)

文章目录 前言一、使用 git clone --depth1 来下载二、修改host文件解决三、谷歌浏览器插件加速四、油猴插件和脚本五、gitclone.com六、Github 加速下载链接七、Github 镜像访问八、使用码云下载参考资料&#xff0c;感谢以下文章 前言 Github上下载仓库或者克隆仓库&#xf…

Docker基础——Centos7安装Docker

0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…

「深度学习之优化算法」(十三)蝙蝠算法

1. 蝙蝠算法简介 (以下描述,均不是学术用语,仅供大家快乐的阅读)   蝙蝠算法(Bat Algorithm)是受蝙蝠回声定位的特性启发而提出的新兴算法,提出时间是2010年,虽然距今(2020)有近10年,但与其它的经典算法相比仍算一个新算法。算法也已有一定规模的研究和应用,但仍…

数据结构 ~ 栈、队列

栈 一个后进先出的数据结构、JS中没有栈&#xff0c;可以使用 Array 模拟 const stack [] stack.push(1) // 入栈 stack.push(2) // 入栈 const item1 stack.pop() // 出栈 const item2 stack.pop() // 出栈以上代码可以使用 nodeJs 断点调试&#xff08;F5启动&#xff0…

【Envi风暴】Envi5.6安装图文教程(附Envi5.6完整版下载)

本文讲解Envi5.6与应用商店app store的安装与使用。 文章目录 一、ENVI5.6安装过程二、app store的安装三、ENVI5.6下载地址一、ENVI5.6安装过程 从文末网盘下载完整的ENVI5.6安装包,如下所示:双击主程序envi56-win.exe,开始安装。 点击Next。 点击Next。 选择安装路径,可…

3.15 Bootstrap 警告(Alerts)

文章目录 Bootstrap 警告&#xff08;Alerts&#xff09;可取消的警告&#xff08;Dismissal Alerts&#xff09;警告&#xff08;Alerts&#xff09;中的链接 Bootstrap 警告&#xff08;Alerts&#xff09; 本章将讲解警告&#xff08;Alerts&#xff09;以及 Bootstrap 所提…

JDK、JRE、JVM之间的关系是什么?

目录 JVM、JRE、JDK的关系&#xff1f; JDK、JRE、JVM都是什么&#xff1f; JVM JRE JDK JVM、JRE、JDK的关系&#xff1f; 三者包含关系&#xff1a; JDK>JRE>JVM JDK、JRE、JVM都是什么&#xff1f; jdk&#xff1a;是用于java开发的最小环境 包括&#xff1a;ja…

8.postgresql--Update join 和 Delete using

Update join Update join用于基于另一张表更新表数据&#xff0c;语法如下&#xff1a; UPDATE t1 SET t1.c1 new_value FROM t2 WHERE t1.c2 t2.c2;CREATE TABLE product_segment (id SERIAL PRIMARY KEY,segment VARCHAR NOT NULL,discount NUMERIC (4, 2) );INSERT INTO…

【JavaEE】DI与DL的介绍-Spring项目的创建-Bean对象的存储与获取

Spring的开发要点总结 文章目录 【JavaEE】Spring的开发要点总结&#xff08;1&#xff09;1. DI 和 DL1.1 DI 依赖注入1.2 DL 依赖查询1.3 DI 与 DL的区别1.4 IoC 与 DI/DL 的区别 2. Spring项目的创建2.1 创建Maven项目2.2 设置国内源2.2.1 勾选2.2.2 删除本地jar包2.2.3 re…

数据中心机房建设,务必确定这13个关键点

下午好&#xff0c;我的网工朋友。 关于机房、机架的相关内容&#xff0c;给你们说了不少。 今天再给你补充个知识点&#xff0c;机房建设&#xff0c;要怎么做。 熟悉机房建设的网工朋友可能都知道&#xff0c;一个全面的数据中心机房建设工程一般包括&#xff1a; 综合布…

VUE- 选取本地图片,自定义裁切图片比例 vue-cropper

裁切图片&#xff0c;按照比例裁切&#xff0c;分步骤 1&#xff1a;el-upload选择本地图片&#xff08;分选择本地和上传两步骤&#xff09; 2&#xff1a;在on-change回调方法中拿到el-upload选中的图片&#xff0c;显示在vueCropper上&#xff08;&#xff09;。 2.1&…

vulnhub靶场red:1教程

靶场搭建 靶机下载地址&#xff1a;Red: 1 ~ VulnHub 难度&#xff1a;中等 信息收集 arp-scan -l 这里没截图忘记了&#xff0c;就只是发现主机 扫描端口 nmap --min-rate 1000 -p- 192.168.21.130 nmap -sT -sV -sC -O -p22,80 192.168.21.130 先看80端口 看到链接点一…

在LLM的支持下使游戏NPC具有记忆化的方法

问题 使用GPT这样的LLM去处理游戏中的NPC和玩家的对话是个很好的点子&#xff0c;那么如何处理记忆化的问题呢。 因为LLM的输入tokens是有限制的&#xff0c;所以伴随着问题的记忆context是有窗口大小限制的&#xff0c;将所有的记忆输入LLM并不现实。 所以这里看到了stanfo…

深度学习开源框架

文章目录 1. 深度学习框架1.1 概述1.2 深度学习框架—关于组件1.2.1 组件—张量1.2.2 基于张量的各种操作1.2.3 计算图1.2.4 自动微分工具1.2.5 拓展包 2. 主流深度学习框架2.1 市面上主流框架2.2 本土深度学习框架2.3 深度学习框架的标准化--ONNX 3. Tensorflow3.1 Tensorflow…

让人恶心的多线程代码,性能怎么优化!

Java 中最烦人的&#xff0c;就是多线程&#xff0c;一不小心&#xff0c;代码写的比单线程还慢&#xff0c;这就让人非常尴尬。 通常情况下&#xff0c;我们会使用 ThreadLocal 实现线程封闭&#xff0c;比如避免 SimpleDateFormat 在并发环境下所引起的一些不一致情况。其实…

【TiDB理论知识 03】TiKV-持久化与数据读取

目录 一 TiKV架构和作用 二 数据持久化 1 RocksDB&#xff1a;写入 写入过程 第一步 &#xff1a;WAL 写日志 &#xff08;磁盘日志&#xff09; 第二步&#xff1a;写MemTable (内存中) 第三步 &#xff1a; 转存为immutable MemTable&#xff08;内存中&#xff09; …

Web 3.0时代,重塑教育与学习方式的可能性

随着科技的快速发展和互联网的普及&#xff0c;教育领域也面临着巨大的机遇和挑战。Web 3.0时代的到来为教育与学习方式带来了全新的可能性。在这个数字化时代&#xff0c;我们可以探索和利用Web 3.0技术&#xff0c;重塑教育的方式&#xff0c;提供更个性化、互动性和灵活性的…